1

我很惊讶 C 不能保证在编译(翻译)时评估某些(常量)表达式。

C11(6.6 常量表达式)(强调):

可以在翻译期间而不是运行时评估常量表达式,...

因此,有两个问题:

  1. 是否有一种标准方法可以保证在编译(翻译)时评估某个(常量)表达式?
  2. 额外的问题:为什么C不保证呢?保证它的(技术)障碍是什么?
4

2 回答 2

1

可能只是对英语的稍微模棱两可的使用:术语“can”在这里(恕我直言)用于表达表达式是编译时可评估的逻辑可能性,而不是可选的实现指令。

如果我们从标准中引用您引用的段落的全文(强调的粗斜体是我的),那么我相信可以保证评估在编译时有效地进行:

6.6 常量表达式
……<br/>

描述
2 常量表达式可以在翻译期间而不是运行时进行计算,因此可以在常量可能存在的任何地方使用

于 2021-04-26T11:01:37.093 回答
1

C 标准通常无助于分别描述编译时和运行时可能发生的事情。整个语言基于 C17 5.1.2.3 中“抽象机器”的(相当无用的)概念

本国际标准中的语义描述描述了与优化问题无关的抽象机器的行为。
...表达式的
评估通常包括值计算和副作用的启动...
在抽象机器中,所有表达式都按照语义指定的方式进行评估。如果一个实际的实现可以推断出它的值没有被使用并且没有产生需要的副作用,则它不需要评估表达式的一部分......

上面包括了评估的正式定义,这也是相当无用的。基本上,只要尊重副作用和“可观察的行为”,实现就可以自由地以优化的方式做任何事情。没有要求说明编译器必须执行某些优化。可以构建一个完全没有优化的编译器,它仍然可以是一个符合要求的实现。

至于 6.6 和常量表达式,其目的肯定是说明生成有效编译时常量的规则。如果整数常量表达式没有在编译时进行评估,那么生成可执行文件就变得非常不切实际,以至于整个语言都会崩溃。间接地,除非在编译时评估常量表达式,否则有许多要求无法满足。

例如,如果在编译时不知道静态存储持续时间对象的数组大小,那么您将如何生成用于初始化它们的启动代码?它必须在 main() 被调用之前发生——这实际上是由 5.1.2 保证的:

所有具有静态存储持续时间的对象都应在程序启动之前进行初始化(设置为其初始值)。

如果 main 包含static int arr [5] = {1,2,3,4,5};,那么当我们到达声明时,这个对象必须已经被初始化。所以我们只能满足 5.1.2 如果5我的例子中的整数常量,一个整数常量表达式,实际上是在编译时计算的。

于 2021-04-26T12:05:48.553 回答