需要澄清常量表达式

Need clarification about constant expressions

K&R c 第 2 版(第 2.3 节)提到

A constant expression is an expression that involves only constants. Such expressions may be evaluated at during compilation rather than run-time, and accordingly may be used in any place that a constant can occur

然而,我对此有几个疑问:

  1. 这个表达式会被认为是常量表达式吗?

    const int x=5;
    const int y=6;
    int z=x+y;
    

    即使用 const 关键字是否被视为常量表达式?

  2. 是否有任何技术可以检查表达式是否在编译期间或 运行 期间被计算?

  3. 是否存在编译时求值与 运行 时求值不同的结果?

  4. 我应该关心它吗? (也许我用它来优化我的程序)

using const keyword is considered constant expression or not?

>> 不,它不是常数。使用const的变量称为const限定,但不是编译时常量。

Is there any technique by which we can check whether an expression was evaluated during compilation or during run-time?

>>Unwind先生的回答中所述)反汇编代码

Are there any cases where compile time evaluation produces different result than run-time evaluation?

>> 不会的。参考章节§6.6 11C11标准。

FWIW,如果使用 sizeof 运算符(编译时,虽然不是常量表达式),NULL 指针取消引用就可以了。编译时 NULL 指针取消引用调用 undefined behaviour.

Should I even care about it? (maybe I use it to optimize my programs)

>>个人观点,所以不会回答。

  1. 也许吧。编译器可以添加更多形式的常量表达式,因此如果它可以向自己证明变量引用足够常量,它就可以在编译时计算表达式。
  2. 您(当然)可以反汇编代码并查看编译器做了什么。
  3. 如果编译器符合标准,则不会。该标准表示 "The semantic rules for the evaluation of a constant expression are the same as for nonconstant expressions"(C11 草案中的 §6.6 11)。
  4. 不多,不。 :) 但是无论如何都要对这样的代码使用 const
  1. x 和 y 是常量,z 不是。编译器可能会替换 x 和 y,但不会替换 z。但可能编译器也会计算 5 + 6 并直接分配给 z。

  2. 不确定您是否可以检查生成的汇编代码,但我不知道如何做到这一点。

  3. 不是。编译时间意味着表达式已经在 运行 时间内计算出来。

  4. 我关心 :) 但它仅在您需要快速执行时才适用。

  1. 在C中,const限定符只是程序员给编译器的保证,他不会改变对象。否则它不像在 C++ 中那样具有特殊含义。具有文件或全局范围的此类对象的 初始化程序 必须是 constant expression.

  2. 作为扩展,gcc 有一个 builtin 函数 (int __builtin_constant_p (exp)) 来确定一个值是否为常量。

  3. 不,它不应该——除非你利用定义的实现未定义的行为并且编译器和目标的行为不同. [1]

  4. 由于 常量表达式 在编译时求值,因此它们的处理时间很安全,并且经常编码 space 和可能的数据 space .此外,在某些地方(例如全局初始化器),只允许 常量表达式 。看标准。


[1]:一个例子是右移一个带符号的负整数常量,例如-1 >> 24。由于这是实现定义的,编译器可能会从程序 运行 使用具有相同值的变量产生不同的结果:

int i = -1;
(-1 >> 24) == (i >> 24)
^             ^--- run-time evaluated by target
+--- compile-time evaluated by compiler

比较可能会失败。