C语言中是否有const关键字?

59

这个问题可能很幼稚,但是:

  • C 语言中有 const 关键字吗?
  • 从哪个版本开始存在?
  • C 语言和 C++ 中的 const 在语义和/或语法上有什么不同吗?

@C.Ross:那种句子让我产生了提问的想法 :) - Armen Tsirunyan
https://dev59.com/sHVC5IYBdhLWcg3w2lGI - Kris
可能是重复问题:https://dev59.com/THE95IYBdhLWcg3wb9hb - Prasoon Saurav
10个回答

64

在涉及到const关键字的情况下,C语言和C++语言之间没有语法差异,除了一个相当晦涩难懂的区别:在C语言中(从C99开始),你可以将函数参数声明为

void foo(int a[const]);

这相当于

void foo(int *const a);

声明。C ++不支持这种语法。

也存在语义差异。正如@Ben Voigt已经指出的,C中const声明不会产生常量表达式,即在C中,您不能在case标签中使用const int对象,也不能作为非VLA数组声明中的位域宽度或数组大小(在C++中均可实现)。此外,在C中,默认情况下,const对象具有外部链接(在C ++中具有内部链接)。

至少还有一个语义差异,Ben没有提到。 C ++语言的常量正确性规则支持以下标准转换

int **pp = 0;
const int *const *cpp = pp; // OK in C++

int ***ppp = 0;
int *const *const *cppp = ppp; // OK in C++

这些初始化在C语言中是非法的。

int **pp = 0;
const int *const *cpp = pp; /* ERROR in C */

int ***ppp = 0;
int *const *const *cppp = ppp; /* ERROR in C */

一般来说,当处理多级指针时,C++允许你在任何间接层级上添加const修饰符,只要你同时将const修饰符添加到顶层指针。

而在C语言中,你只能给顶层指针所指向的类型添加const修饰符,而不能更深层次。

int **pp = 0;
int *const *cpp = pp; /* OK in C */

int ***ppp = 0;
int **const *cppp = ppp; /* OK in C */

同一基本原则的另一个表现形式是C和C++中数组的const-correctness规则。在C++中,您可以执行以下操作:

int a[10];
const int (*p)[10] = &a; // OK in C++

尝试在C语言中做相同的事情将导致错误。
int a[10];
const int (*p)[10] = &a; /* ERROR in C */

9
+1 不知道 C 和 C++ 之间的具体区别。 - David Rodríguez - dribeas

15

这里回答了前两个问题:C语言中的const

在C和C++中,const的语义存在相当大的差异。

  • 在C++中,适当类型的const变量是整型常量表达式(如果它们的初始值是编译时常量表达式),可以在需要的上下文中使用,例如数组边界和枚举定义。在C中,它们不是并且不能成为。

  • 在C++中,const全局变量自动具有static链接性,因此可以将它们放在头文件中。在C中,这样的变量具有外部链接性,并且会在链接时生成重复定义错误。


这些差异是什么? :) - Armen Tsirunyan
3
耐心,年轻的学徒,要有耐心。 - Ben Voigt
我看到我们再次相遇了,邦德先生...或者我应该说沃伊特先生?你曾经在 comp.lang.c++ 上回答过我的问题,那是很久很久以前的事情了 :) - Homunculus Reticulli
在C++中,适当类型的const变量可以是整数常量表达式 - 但并非所有情况都是如此。我想这就是为什么在ISOC++11中添加consexpr关键字的主要原因。例如:int i = 0; std :: cin >> i; const int I = i; int is [I]; 根据标准,最后一个命令是不合法的,因为I不是静态表达式,但它是一个常数变量。因此,更正确的说法应该是:“在C ++中,适当类型的const变量可以是整数常量表达式,但在C中则永远不行。” - Dániel Sándor

9
是的,有一个const关键字。它是作为1989年标准的一部分添加的。
至于兼容性,以下是Harbison&Steele第5版中的一段话:
具有类型限定符const但没有显式存储类的顶级声明在C ++中被认为是静态的,在C中则是extern。为保持兼容性,请检查顶级const声明并提供显式存储类。
在C ++中,字符串常量隐式地是const;而在C中不是。

7

是的,const 自至少 ANSI C(又称 C89)以来就一直存在。

在我手头的 "The C Programming Language (2nd Edition)", Kernighan & Ritchie(1988 年出版)中,它显然就已经出现了。

相关摘录:

constvolatile 属性是 ANSI 标准中的新内容。 const 的目的是声明可以放置在只读内存中的对象,并可能提高优化机会。


1
ANSI C不仅仅是C89。 - Peter Mortensen
@PeterMortensen:是的,也许我应该说“自从第一个ANSI C(又称C89)”,但正如维基百科文章中所指出的:“历史上,名称[ANSI C]特指标准的原始和最佳支持版本(称为C89或C90)。”,以及“这个版本[C89]的语言通常被称为ANSI C”。 - GrahamS

5

另外两个区别:


2
在C语言中,语义与C++不同。例如,
unsigned const a = 10;
unsigned A[a];

C++中,文件作用域是有效的,但在C中不是。


2

是的,在C语言中,从C89开始就有const关键字。

这里有一篇很好的文章,讲述了C语言中const关键字的行为:behaviour of const keyword in C


C89,实际上(或C90,无论它实际上被称为什么)。 - Kris

1

是的,C语言中有一个const关键字。它从C90版本开始就存在了。

从语法上讲,它可以出现在与C++相同的位置。从语义上讲,它可能会更加宽松,如果我没记错的话。


1

1
在C语言中有一个“const”关键字,它已经存在了很长时间。如果一个变量被指定为“const”,则禁止对其进行写操作。
此外,在某些环境中,声明为“const”的变量可能位于与其他变量不同的数据段中。这个数据段可能提供硬件写保护,并且对于嵌入式系统,可能存储在ROM或闪存中,而不是RAM中(这在一些处理器上非常重要,这些处理器的ROM或闪存比RAM多得多,例如128 KB闪存和3.5 KB RAM,或2 KB ROM和96字节RAM)。
请注意,编译器通常不会对“const”值或涉及它们的表达式进行任何推断。如果我说“const char foo [] =“Hello”;”,然后稍后引用foo [1],编译器将从存储foo []的位置加载值(最可能是'e')并使用加载的值。有时这有助于在编译后的代码映像中修补值,但有时它只是浪费代码。
如果您想定义一个编译时“可替换”的常量,至少对于整数常量来说,最好的方法可能是使用“枚举”。例如,“enum {woozle=19;}”将导致19在整个代码中替换为“woozle”。请注意,与文本替换不同,枚举声明遵守适当的作用域规则。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接