【问题标题】:String Literal address across translation units [duplicate]跨翻译单元的字符串文字地址[重复]
【发布时间】:2014-12-04 10:55:11
【问题描述】:

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

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

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

【问题讨论】:

  • 不,你不能依赖这个。
  • @NeilKirk 谢谢尼尔,我已经编辑并添加了第二个问题。它背后的任何理由都会有很大的启发。
  • @fanl - Visual C++ 编译器套件具有“字符串池”选项,其中相同的文字将具有相同的指针值。最后一句中的关键词是option。这意味着您不能相信指针值相等。
  • 我想合理的是允许更快的编译。字符串池化是有代价的。
  • @Alnitak 字符串文字不是 const 字符串?

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


【解决方案1】:

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

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

对于 C++,这在草案标准部分 2.14.5 String literals 中有所涉及:

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

允许编译器pool字符串文字,但你必须了解它是如何在编译器之间工作的,所以这不是可移植的,并且可能会改变。 Visual Studio 包含一个option for string literal pooling

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

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

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

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

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

注意,使用attemptif ... support it

至于至少对于 C 不需要 字符串文字 进行池化的基本原理,我们可以从 archived comp.std.c discussion on string literals 中看到,基本原理是由于当时的各种实现:

GCC 可能是一个例子,但不是动力。部分地 希望在 ROMmable 数据中包含字符串文字是为了支持,呃, 只读存储器。我隐约记得使用过几个 C 实现 (在做出 X3J11 决定之前)字符串文字是 自动汇集或存储在恒定数据程序部分。 鉴于现有的各种实践和容易获得的 需要原始 UNIX 属性时的解决方法,似乎 最好不要试图保证字符串的唯一性和可写性 文字。

【讨论】:

  • 您的意思是,如果翻译单元之间和内部的地址相同,那么两者都不可靠?
  • @fanl 他是这么说的。在最初的 K&R C 中,每个字符串文字都保证是唯一的,具有不同的地址(并且您可以修改字符串文字);最初的 C 标准改变了这一点,并且 允许 相同的字符串文字具有相同的地址。
  • @fanl 即使编译器支持池化,它在所有情况下都不可靠,gccVisual Studio 在他们的文档中都指出它仅适用于某些情况
【解决方案2】:

,您不能指望同一个地址。如果它发生,就会发生。但是没有强制执行它。

§ 2.14.5/p12

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-16
    • 1970-01-01
    • 2010-10-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多