【问题标题】:C++: int calculations during compile time (not during running time)C ++:编译期间的int计算(而不是运行期间)
【发布时间】:2020-09-15 10:37:22
【问题描述】:

简单的问题:

为什么下面的代码有效?

int main() {
    const int a = 4;
    const int b = 16;
    const int size = b/a;
    int arr[size] = {0,1,2,3};
    return 0;
}

我认为静态数组的大小必须在编译时定义,因此只能使用“int”字面量。在上面的代码中,尽管大小是一个计算,但代码会编译。这个计算是在编译期间完成的吗?

如果是,可能我对编译和运行的理解是错误的:编译只是通过语法,将代码翻译成机器码,但不做任何计算……

谢谢!

【问题讨论】:

标签: c++ arrays compilation


【解决方案1】:

这个计算是在编译期间完成的吗?

是的,编译器为你做了很多优化和计算,你的代码中的初始化即使没有任何优化也是可以的,这是编译器预先计算的结果。

这里的计算一般包括constexprconst类型声明等,它们已经在语言本身的定义中了(见constant expression)。

compile-time const and example

只看示例的输出。

compile-time constexpr and example

constexpr 说明符声明可以在编译时评估函数或变量的值。


This is how array can be initialized,数组声明如下:

noptr-declarator [ expr(可选) ] attr(可选)

这里,expr 是:

一个整型常量表达式(C++14 前)一个 std::size_t 类型的转换常量表达式(C++14 起),它的计算结果大于零

都是constant expression,上面写着:

一个可以在编译时计算的表达式

那么,使用所谓的预计算来初始化一个数组是可以的。

这里还有一个后续:还有很多方法可以通过让它们在编译期间完成来节省更多计算和时间,它们在上面的链接中显示。


顺便说点不一样的:至于优化,在计算从1到100的总和时,可以看到-O0-O3版本的汇编代码的区别,简直是下巴了-breaker -- 你会在-O3版本的汇编代码中看到结果5050,它也是一种编译时计算,但不是针对各种情况启用的。

【讨论】:

  • 如果有标准的相关段落在这里会很高兴
  • @SebastianHoffmann 不知道这个版本够不够完整。
  • 这里要小心:问题不是“某些编译器会在编译时进行此计算并最终得到数组大小的常量”;它是“语言定义是否要求它起作用”。这是两个不同的东西。如果它需要工作,优化设置不会影响它。
  • @PeteBecker,啊,这只是后续。我会将它们添加到我的答案中,谢谢。
【解决方案2】:

我认为静态数组的大小必须在编译时定义,因此只能使用“int”字面量。

第一部分是正确的,但第二部分只是在 c++11 之前才正确(你也可以这样做const int i = 1 + 2)。从 c++11 开始,规则说初始化表达式被 求值 以查看它是否产生一个常量表达式。

还有一个规则是 const 整数类型隐式为 constexpr(即在编译时计算),只要初始化表达式在编译时是可计算的。

所以在这个表达式中:

const int size = b/a;

变量size必需在编译时计算的,只要表达式a/b是一个常量表达式。由于ab也是用字面量初始化的const ints,所以size的初始化是一个常量表达式。 (请注意,从任何声明中删除 const 将使 size 成为非常量表达式)。

所以size需要在编译时计算(编译器在这件事上别无选择,不管优化如何),所以它可以用作数组维度。

这里是完整的rules,它是如何工作的。

【讨论】:

    猜你喜欢
    • 2014-12-23
    • 2011-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-14
    相关资源
    最近更新 更多