字符串翻译单元的文字地址

时间:2014-10-09 13:26:03

标签: c++ c string string-literals pooling

我想询问是否可以通过翻译单元依赖字符串文字地址?即:

给定文件foo.c引用了字符串文字"I'm a literal!",是否正确且可移植以依赖于其他给定文件{1}},相同的字符串文字 bar.c将具有相同的内存地址?考虑到每个文件将被翻译为单个"I'm a literal!"文件。

为了更好地说明,请遵循示例代码:

.o

一个gcc示例命令行:

# File foo.c
/* ... */
const char * x = "I'm a literal!"

# File bar.c
/* ... */
const char * y = "I'm a literal!"

# File test.c
/* ... */
extern const char * x;
extern const char * y;
assert (x == y); //Is this assertion going to fail?

在同一个翻译单元怎么样?如果字符串文字在相同翻译单元中,那么这是否可靠?

2 个答案:

答案 0 :(得分:12)

您不能依赖具有相同内存位置的相同字符串文字,这是一个实现决策。 C99 draft standard告诉我们,从6.4.5 字符串文字部分开始,未指定相同的字符串文字是否不同:

  

未指明这些数组是否与它们不同   元素具有适当的值。如果程序试图   修改这样的数组,行为是未定义的。

对于C ++,标准草案部分草案2.14.5 字符串文字中包含:

  

是否所有字符串文字都是不同的(即存储在   非重叠对象)是实现定义的。的效果   尝试修改字符串文字是未定义的。

允许编译器 pool 字符串文字,但你必须了解它如何从编译器到编译器工作,因此这将不可移植并且可能会发生变化。 Visual Studio包含option for string literal pooling

  

在某些情况下,可以合并相同的字符串文字以节省空间   在可执行文件中。在字符串文字池中,编译器会导致   对特定字符串文字的所有引用都指向相同的字符串   在内存中的位置,而不是每个参考点到一个   单独的字符串文字实例。要启用字符串池,请使用   / GF编译器选项。

请注意,它确实符合在某些情况下

gcc支持汇总和跨编译单元,您可以通过-fmerge-constants启用它:

  

尝试合并相同的常量(字符串常量和   编译单元中的浮点常量。

     

如果是汇编程序,则此选项是优化编译的默认选项   和链接器支持它。使用-fno-merge-constants来抑制它   行为。

请注意,使用尝试如果......支持

至于对于不要求字符串文字的C至少为C的理由,我们可以从archived comp.std.c discussion on string literals看到理由是由于当时的各种实现:

  海湾合作委员会可能是一个例子,但不是动机。部分是   希望在ROMmable数据中包含字符串文字是为了支持,呃,   ROMming。我依旧回忆起曾使用过几个C实现   (在做出X3J11决定之前)字符串文字是其中之一   自动汇集或存储在常量数据程序部分中。   鉴于现有的各种实践和易于使用的可用性   看起来好像是原始的UNIX属性   最好不要试图保证字符串的唯一性和可写性   文字。

答案 1 :(得分:4)

,您不能指望相同的地址。如果它发生,发生。但没有什么可以强制执行的。

§2.14.5/ p12

  

是否所有字符串文字都是不同的(即存储在   非重叠对象)是实现定义的。的效果   尝试修改字符串文字是未定义的。

编译器可以随心所欲。如果它们位于不同的翻译单元中,或者即使它们位于同一个翻译单元中,它们也可以存储在不同的地址中,而不管它们是只读存储器。

例如,在MSVC上,地址在两种情况下都完全不同,但同样:没有什么能阻止编译器合并指针的值(甚至,其中,只读只读)部分约束是有义务的。)