非整数常量在 C++ 中如何工作?[复制]

How do non-integral constants work in C++? [duplicate]

提问人:sbi 提问时间:7/16/2014 最后编辑:Communitysbi 更新时间:7/16/2014 访问量:321

问:

所以我知道在 C++ 中,常量默认与变量的链接不同。这就是为什么我不能把

int foo;

在某些标题中 - 链接器将正确地抱怨多个定义。OTOH,我可以写

const int bar = 42;

,编译器确保只有一个定义。bar

使用积分常量,很容易看出编译器如何处理这个问题——至少只要没有人获取它的地址或做一些其他有趣的事情,要求它为它分配存储)。但是,如果有人这样做了怎么办?如果它不是一个整体,而是需要在运行时执行代码的东西呢?假设我把它放到一个标题中:bar

const std::string baz = "h2g2";

假设没有小的字符串优化,这需要在运行时分配动态内存,因此需要执行代码,需要将地址存储在某个地方,等等。

我假设我最终会得到每个翻译单元的一个定义,只是编译器为其分配了内部链接以防止链接器抱怨?还是我错过了什么?baz

注意:我对 constexpr感兴趣,只对普通的旧 C++ 常量感兴趣,因为它们自 80 年代以来就存在,并且是用 C++98 编纂的。(但是,如果一个全面的答案包括这一切如何与 constexpr 结合在一起,我不会抱怨这一点。

C++ 常量链接 C++98

评论

0赞 Jason S 7/16/2014
您的意思是非原始类型的常量。浮点常量的工作方式与整数常量相同。
0赞 sbi 7/16/2014
@TemplateRex:我添加了注释来解释这一点。
0赞 MSalters 7/16/2014
@JasonS:嗯,不完全是 - 例如,它们不能是积分常量表达式。
0赞 Mike Seymour 7/16/2014
“编译器确保只有一个定义”——不,它没有。它给了它内部链接(就好像你已经声明了它一样),这样它就可以被乘以定义。barstatic
1赞 Mike Seymour 7/17/2014
@JasonS:基本上,以需要定义的方式使用(例如获取其地址)。完整的定义相当复杂;如果您想要血腥的细节,请参阅 C++ 标准的第 3.2 节。“ODR”代表“一个定义规则”,即确定何时以及如何定义事物的规则。

答:

4赞 Marco A. 7/16/2014 #1

默认情况下,像在 C++ 中那样声明对象(在命名空间范围内)会为其分配内部链接。const

如果声明(并因初始化而定义)

const std::string baz = "h2g2";

在标题中,每个翻译单元都有一个静态链接的字符串。地址必须存储在每个转换单元中(每个不同的非堆存储字符文本的不同地址 - 只读内存)

编辑:正如 C++11 题外话所暗示的那样,因为它的意思是“适用于常量表达式评估”,因此它也应该具有内部链接。[注意:我没有提到C++14]constexprconst

评论

0赞 MSalters 7/16/2014
SSO(小字符串优化)适用于 的内容,而不是字符串文字。你的最后一句话似乎混淆了两者;SSO 无法影响文本bazchar[]
0赞 Marco A. 7/16/2014
@sbi在这种情况下,不应发生 SSO,因为数据是 char 文本,其地址在编译时是已知的
1赞 rubenvb 7/16/2014
@Marco注意的是,在C++14中,“暗示”部分是不真实的,因此应该依赖nog。constexprconst
0赞 Marco A. 7/16/2014
谢谢ruben,如果有人没有看到你的评论,我会把它添加到答案中
2赞 R. Martinho Fernandes 7/16/2014
但是,请注意,“暗示”对于变量确实是正确的,即使在 C++14 中也是如此。constexprconst