考虑下面的代码;
#define A 5
#define B 3
int difference = A - B;
是在编译时将“difference”的值硬编码为“2”,还是在运行时进行计算?
最佳答案
A
和B
宏有点让人分心。这:
#define A 5
#define B 3
int difference = A - B;
与此完全相同:
int difference = 5 - 3;
因此,让我们讨论后者。
5 - 3
是一个常量表达式,它是一个“可以在翻译过程中而不是在运行时求值的表达式,因此可以在常量可能存在的任何位置使用”。它也是一个* integer常量表达式。例如,case标签必须是一个整数常量表达式,因此您可以这样编写:switch (foo) {
case 2: /* this is a constant */
...
}
或这个:
switch (foo) {
case 5 - 3: /* this is a constant expression */
...
}
但是请注意,该定义表明可以在翻译过程中对其进行评估,而并非必须如此。有些上下文需要常量表达式,在这些上下文中,必须在编译时对表达式求值。
但是,假设在某个函数中声明了
difference
,则初始化器不是这些上下文之一。任何值得您付费的编译器(即使它是免费的)也将在编译时将
5 - 3
减少为2
,并生成将2
值存储在difference
中的代码。但这不是必需的。 C标准规定了程序的行为;它没有指定必须如何实现该行为。但是可以肯定地认为,无论您使用的是哪种编译器,都将5 - 3
替换为2
。即使您写:
int difference = 2;
编译器可以合法地生成代码,将值
5
加载到寄存器中,从中减去3
,然后将寄存器的内容存储到difference
中。那将是一件愚蠢的事情,但是语言标准并未排除它。只要最终结果是
difference
的值为2
,语言标准就不会在意它的完成方式。另一方面,如果您写:
switch (foo) {
case 5 - 3: /* ... */
case 2: /* ... */
}
那么编译器必须计算结果,以便可以诊断错误(不能有两个具有相同值的case标签。
最后,如果您在文件作用域(任何函数之外)定义
difference
,则初始值必须为常数。但是,在这种情况下,真正的区别不在于是否在编译时评估5 - 3
,而是是否允许使用非常量表达式。引用:2011 C标准的最新草案为N1570(大PDF);常量表达式将在6.6节中讨论。
关于c - 常数之间的算术运算,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/9627700/