字符串跨翻译单位的文字地址

String Literal address across translation units

本文关键字:文字 地址 单位 翻译 字符串      更新时间:2023-10-16

我想问一下,在翻译单元之间依赖字符串文字地址是否可以移植?I.e:

给定的文件foo.c引用了字符串文字"I'm a literal!",在其他给定的文件(例如bar.c)中,相同的字符串文字"I'm a literal!"将具有同一内存地址,这是否正确且可移植?考虑到每个文件都将被翻译成一个单独的.o文件。

为了更好地说明,下面是一个示例代码:

# 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?

还有一个gcc命令行示例:

gcc -c -o foo.o -Wall foo.c
gcc -c -o bar.o -Wall bar.c
gcc -c -o test.o -Wall test.c
gcc -o test foo.o bar.o test.o

在同一个翻译单元里呢?如果字符串文字在相同的翻译单元中,这是否可靠?

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

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

对于C++,这在标准草案2.14.5字符串文本中有介绍,其中写道:

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

编译器可以字符串文字,但您必须了解它在不同编译器之间的工作方式,因此这是不可移植的,可能会发生变化。Visual Studio包含一个字符串文字池选项

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

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

gcc确实支持池化和跨编译单元,您可以通过-fmerge常量打开它:

尝试合并相同的常量(字符串常量和浮点常量)。

如果汇编程序并且链接器支持它。使用-fno merge常量可以禁止行为

注意,尝试的使用如果。。。支持它

至于C不需要合并字符串文字的基本原理,我们可以从这篇存档的comp.std.C关于字符串文字的讨论中看到,基本原理是由于当时实现的多样性:

海湾合作委员会可能是一个例子,但不是动机。部分原因是希望在可ROM数据中具有字符串文字是为了支持呃,ROMming。我隐约记得曾经使用过几个C实现(在做出X3J11决策之前)字符串文字是自动汇集或存储在恒定数据程序部分中。考虑到现有的各种实践和当需要原始的UNIX属性时最好不要试图保证字符串的唯一性和可写性文字。

,不能期望相同的地址。如果它发生了,就会发生。但没有任何强制措施。

§2.14.5/12

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

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

例如,在MSVC上,这两种情况下的地址完全不同,但同样:没有什么能阻止编译器合并指针的值(即使是中的,只要只读部分约束是强制性的)。