我正在读一本提到这个的书
如果编译器知道每次使用const,则无需分配 空间来容纳它。例如:
const int c1=1;
const int c3=my_f(3);
- 醇>
extern const int c4;
鉴于c3和c4的值不称为编译时,存储 必须分配给c3和c4。
我不明白这一点。我的怀疑是:
抱着这里意味着什么?难道它还不需要将所有内容存储在内存中吗? 对于c1,我们不会有任何存储分配吗?
请清除我的怀疑。
谢谢。
答案 0 :(得分:4)
c1
与其他两个常量不同,它是用文字值初始化的。这使得编译器可以在使用常量的任何地方放置该值,如下所示:
int x = z + c1;
可以替换为
int x = z + 1;
这意味着编译器不需要分配空间并在其中存储1
。
c3
和c4
不同:一个是使用函数计算的,另一个是从不同的编译单元提供的。这意味着编译器不能再以c1
的方式执行替换:编译器不知道c3
和c4
的值。因此编译器会为
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
更严格。只有c1
和c2
可以是constexpr
。 c3
也可以,但也需要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
个函数可以在这个区域完成更多工作。