考虑下面的代码;

#define A 5
#define B 3

int difference = A - B;

是在编译时将“difference”的值硬编码为“2”,还是在运行时进行计算?

最佳答案

AB宏有点让人分心。这:

#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/

10-11 21:14