常量变量的存储分配

Storage allocation to const variables

本文关键字:分配 存储 变量 常量      更新时间:2023-10-16

我正在读一本书,其中提到了这个

如果编译器知道 const 的每次使用,则无需分配 容纳它的空间。例如:

  1. const int c1=1;
  2. const int c3=my_f(3);
  3. extern const int c4;

鉴于 c3 和 c4 的值不称为编译时,存储 必须为 C3 和 C4 分配。

我对此一无所知。我的疑问是:

抱在这里是什么意思?它是否仍然需要将所有内容存储在内存中?对于 c1,我们没有任何存储分配吗?

请消除我的疑虑。

谢谢。

c1与其他

两个常量的不同之处在于它是用文字值初始化的。这允许编译器将该值放在使用常量的任何位置,如下所示:

int x = z + c1;

可以替换为

int x = z + 1;

这意味着编译器不需要在其中分配空间和存储1

c3c4是不同的:一个是使用函数计算的,另一个是从不同的编译单元提供的。这意味着编译器不能再像c1那样执行替换:编译器不知道c3c4的值。因此,编译器生成代码

int x = z + c4;
就像

c4是存储在内存中某个位置的变量一样。由于在这种情况下c4是一个外部常量,链接器将解析其位置,并填写编译器缺少的信息(即c4的地址(,以使程序完成并准备好运行。

Const 有 2 种用途 - 替换宏(常量表达式(和不可变数据。

此声明:

const int c1=1;

本质上是此的类型安全版本:

#define c1 1

这样,这段代码:

int foo = c1;

可以简单地编译为:

int foo = 1;

哪个更有效率。

另一方面,这:

const int c3=my_f(3);

用作不可变的 c3。它可能存在于内存中,但您无法修改它。它本质上是int c3=my_f(3);更安全的版本。

为了说明这一点:

int a1[c1];
int a2[c3];
A1

是有效的,因为编译器可以将 A1 推导出为常量表达式。 A2 不是,因为虽然 C3 是 const,但在编译时可能不知道。

C++11 添加了与 const 类似的 constexpr 关键字,但比 const 更严格。只有c1c2才能constexpr. c3也可能是,尽管它要求my_f也是。

作为积分常量表达式,编译器完全有权使用常量折叠将其从程序中删除。只有当你拿它的地址时,这才不正确。此外,如果可能的话,现代优化编译器可以使用 LTO、内联和常量折叠来对 c3 和 c4 执行相同的操作。

如果不获取变量的地址,则编译器没有义务根据 as-if 规则生成具有等效结果的代码,则编译器没有义务分配该变量。

编辑:常量折叠是编译器在编译时而不是运行时计算表达式的地方。例如,您可以合法地执行在编译时计算3 + 4 int x[3 + 4];。一些例子,特别是那些涉及内燃机的例子,是标准规定的,但如果可能的话,实施可以执行更多。LTO 是链接时间优化,当翻译单元链接在一起时,编译器会跨翻译单元执行优化。

这意味着编译器可以内联 my_f 的主体,然后(取决于主体(常量折叠它以使其成为常量表达式c3,然后常量将其折叠到使用它的地方而不分配它。对于c4,LTO可能会产生c4的值作为常量表达式,在这种情况下,它也可以被常量折叠和删除。

在C++11中,有constexpr功能允许在该地区做更多工作。