【问题标题】:Need clarification about constant expressions需要澄清常量表达式
【发布时间】:2015-07-08 14:06:31
【问题描述】:

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

常量表达式是只包含常量的表达式。这样的表达式可以在编译期间而不是运行时进行评估,因此可以在任何可能出现常量的地方使用

但是,我对此有几个疑问:

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

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

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

  2. 是否有任何技术可以检查表达式是在编译期间还是在运行时评估的?

  3. 是否存在编译时评估与运行时评估产生不同结果的情况?

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

【问题讨论】:

  • 阅读standard; K&R 不是标准,而且已经过时了。

标签: c constant-expression


【解决方案1】:
  1. 也许吧。编译器可以添加更多形式的常量表达式,因此如果它可以向自己证明变量引用足够常量,它就可以在编译时计算表达式。
  2. 您(当然)可以反汇编代码,看看编译器做了什么。
  3. 如果编译器符合标准,则不会。标准规定“常量表达式求值的语义规则与非常量表达式相同”(C11 草案中的第 6.6 11 节)。
  4. 不是很多,不。 :) 但是无论如何都要使用const 来编写这样的代码!

【讨论】:

  • 先生,请问答案3? NULL-dereference 会产生不同的结果,如果我没记错的话。请指教。
  • @SouravGhosh 据我所知,您不能取消引用常量表达式中的指针?您可以将指针(包括NULL)与sizeof 一起使用,但不能进行独立的解引用。
  • 是的,我只是在想这个,对。我会相应地更新我的答案。谢谢。
【解决方案2】:

使用 const 关键字算不算常量表达式?

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

是否有任何技术可以检查表达式是在编译期间还是在运行时评估的?

>>(正如Unwind先生的回答中提到的)反汇编代码。

是否存在编译时评估与运行时评估产生不同结果的情况?

>> 不,不会。请参阅章节§6.6 11、C11 标准。

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

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

>> 基于意见,所以不会回答。

【讨论】:

    【解决方案3】:
    1. x 和 y 是 const,z 不是。编译器可能会替换 x 和 y ,但不会替换 z。但可能编译器也会计算 5 + 6 并直接分配给 z。

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

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

    4. 我在乎 :) 但它只适用于您需要快速执行的情况。

    【讨论】:

      【解决方案4】:
      1. 在 C 中,const 限定符只是程序员向编译器提供的保证,即他不会更改对象。否则,它没有 C++ 中的特殊含义。具有文件或全局范围的此类对象的 initializer 必须是 constant expression。

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

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

      4. 由于 常量表达式 在编译时进行评估,因此它们可以确保处理时间以及代码空间和数据空间的安全。此外,在某些地方(例如全局初始化器),只允许 常量表达式。见标准。


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

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

      比较可能会失败。

      【讨论】:

        猜你喜欢
        • 2011-05-07
        • 1970-01-01
        • 2011-11-09
        • 2012-07-18
        • 1970-01-01
        • 2023-03-09
        • 1970-01-01
        • 2014-12-26
        • 1970-01-01
        相关资源
        最近更新 更多