我想询问是否可以通过翻译单元依赖字符串文字地址?即:
给定文件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?
在同一个翻译单元怎么样?如果字符串文字在相同翻译单元中,那么这是否可靠?
答案 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上,地址在两种情况下都完全不同,但同样:没有什么能阻止编译器合并指针的值(甚至,其中,只读只读)部分约束是有义务的。)