为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C++ C
RISEBY 2019-11-02 14:36:27
我想问一下跨翻译单元依靠字符串文字地址是否可移植?即:给定文件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.cgcc -c -o bar.o -Wall bar.cgcc -c -o test.o -Wall test.cgcc -o test foo.o bar.o test.o在同一个翻译单元中呢?如果字符串文字位于同一翻译单元中,这是否可靠?
查看完整描述

2 回答

?
桃花长相依

TA贡献1860条经验 获得超8个赞

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


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


对于C ++,这在草案标准部分的2.14.5 字符串文字中进行了说明,该文字说:


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


编译器允许池字符串常量,但你必须了解它的编译器是如何工作的编译器,因此这不会是便携,可能会改变。Visual Studio包含用于字符串文字池的选项


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


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


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


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


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


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


至于至少下不需要的理由字符串常量被合并,我们由此可以看出在字符串文字存档comp.std.c讨论的理由是由于各种各样的时候实现的:


GCC可能只是一个例子,但不是动机。在ROMmable数据中使用字符串文字的部分原因是为了支持ROMming。我隐约记得使用了C的两个实现(在做出X3J11决定之前),在这些实现中字符串文字被自动合并或存储在常量数据程序部分中。考虑到现有的各种实践以及当需要原始UNIX属性时可以使用的简便解决方法,似乎最好不要尝试保证字符串文字的唯一性和可写性。


查看完整回答
反对 回复 2019-11-02
?
慕神8447489

TA贡献1780条经验 获得超1个赞

不,您不能期望使用相同的地址。如果发生这种情况,就会发生。但是并没有强制执行。


§2.14.5 / p12


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


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


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


查看完整回答
反对 回复 2019-11-02
  • 2 回答
  • 0 关注
  • 489 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信