2014-10-09 73 views
6

我想问问它是否可移植性依赖跨翻译单元的字符串文字地址?即:字符串跨翻译单元的文字地址

给定文件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 

什么关于同一翻译单元?如果字符串文字在相同的翻译单元中,这是否可靠?

+7

不,你不能依靠这个。 – 2014-10-09 13:27:41

+0

@NeilKirk谢谢Neil,我已经编辑并添加了第二个问题。任何背后的理由都会有很大的启发。 – 2014-10-09 13:30:29

+2

@fanl - Visual C++编译器套件有一个“字符串池”的选项,其中相同的文字将具有相同的指针值。最后一句中的关键词是* option *。这意味着你不能相信指针值是相等的。 – PaulMcKenzie 2014-10-09 13:37:49

回答

10

你不能依靠相同的字符串文字具有相同的内存位置,这是一个实现的决定。该C99 draft standard告诉我们,这是不确定的相同的字符串字面是否是不同的,从部分6.4.5字符串字面

这些阵列是否提供了不同的 元素具有适当的值是不确定的。如果程序试图修改这样一个数组, 的行为是未定义的。

对于C++中,这涵盖在其中说的草案标准部2.14.5字符串文字

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

编译器允许字符串常量,但你必须了解它的编译器是如何工作的编译器,因此这不会是便携,可能会改变。 Visual Studio中包括option for string literal pooling

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

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

gcc不支持池和整个编译单元,你可以通过-fmerge-constants开启:

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

如果汇编器 和链接器支持它,此选项是优化编译的默认值。使用-fno-merge-constants来禁止这种行为 行为。

说明,使用尝试如果...支持

至于至少下不需要字符串文字的理由来汇集,我们可以从这个archived comp.std.c discussion on string literals的理由,以当时的各种实施的是由于看到:

GCC可能是一个例子,但不是动机。部分 希望在ROMmable数据中具有字符串文字是为了支持ROM,ROM。我依稀记得使用了几个C实现 (在X3J11做出决定之前),其中字符串文字是 自动合并或存储在常量数据程序部分。 考虑到现有的各种练习以及在想要使用原始UNIX属性时易于使用的问题,最好不要保证字符串 的唯一性和可写性。

+1

你的意思是说,期待地址在翻译单位内和翻译单位内是相同的,是不可靠的? – 2014-10-09 13:31:51

+2

@fanl他就是这么说的。在原来的K&R C中,每个字符串文字都被保证是唯一的,并且具有不同的地址(并且允许您修改字符串文字)。原来的C标准改变了这一点,并且_permitted_相同的字符串文字具有相同的地址。 – 2014-10-09 13:56:54

+0

@fanl即使编译器支持共享,在所有情况下它都不可靠,gcc和Visual Studio都在其文档中指出它仅适用于某些情况。 – 2014-10-15 15:12:31

3

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

§2.14.5/P12

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

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

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