存储分配给const变量

时间:2012-01-14 15:39:45

标签: c++ const storage

我正在读一本提到这个的书

  

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

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

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

我不明白这一点。我的怀疑是:

抱着这里意味着什么?难道它还不需要将所有内容存储在内存中吗? 对于c1,我们不会有任何存储分配吗?

请清除我的怀疑。

谢谢。

3 个答案:

答案 0 :(得分:4)

c1与其他两个常量不同,它是用文字值初始化的。这使得编译器可以在使用常量的任何地方放置该值,如下所示:

int x = z + c1;

可以替换为

int x = z + 1;

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

c3c4不同:一个是使用函数计算的,另一个是从不同的编译单元提供的。这意味着编译器不能再以c1的方式执行替换:编译器不知道c3c4的值。因此编译器会为

生成代码
int x = z + c4;

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

答案 1 :(得分:2)

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添加constexpr关键字,类似于const,但比const更严格。只有c1c2可以是constexprc3也可以,但也需要my_f

答案 2 :(得分:1)

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

如果你不接受变量的地址,编译器没有义务分配它,如果它可以在as-if规则下生成具有相同结果的代码。

编辑:常量折叠是编译器在编译时而不是运行时评估表达式的地方。例如,您可以合法地执行int x[3 + 4];,其中3 + 4在编译时进行评估。一些示例,特别是那些涉及ICE的示例,是标准规定的,但如果可能,实现可以执行更多。 LTO是链接时间优化,编译器在链接时将翻译单元执行优化。

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

在C ++ 11中,有constexpr个函数可以在这个区域完成更多工作。