我很难理解这段代码中的原因:
#include <cstdio>
void use(const char *msg) { printf("%s\n", msg); }
void bar() { use("/usr/lib/usr/local/foo-bar"); }
void foo() { use("/usr/local/foo-bar"); }
int main() {
bar();
foo();
}
编译器(在我的例子中是 GCC 4.9)决定共享字符串文字:
$ g++ -O2 -std=c++11 foo.cpp && strings a.out | grep /usr/
/usr/lib/usr/local/foo-bar
但在相同但不同的情况下:
#include <cstdio>
void use(const char *msg) { printf("%s\n", msg); }
void bar() { use("/usr/local/var/lib/dbus/machine-id"); } // CHANGED
void foo() { use("/var/lib/dbus/machine-id"); } // CHANGED
int main() {
bar();
foo();
}
它没有:
$ g++ -O2 -std=c++11 foo.cpp && strings a.out | grep /lib/
/usr/local/var/lib/dbus/machine-id
/var/lib/dbus/machine-id
编辑:
对于 -Os
,第二对字符串也被共享。但这没有意义。只是传递指点。具有常量偏移量的 lea
很难被认为是性能恶化,只允许在空间优化模式下共享。
字符串文字共享似乎有大小限制(30,包括终止 NUL)。这也没什么意义,除了可能避免链接器运行过长,试图找到常见的后缀。
最佳答案
This论文对 gcc 和这个主题有很好的研究。我个人并不知道 -fmerge-all-constants
,但您可以检查这是否使字符串在两种情况下重叠(正如论文所述,它不适用于 O3
和 Os
)。
编辑
由于有一个有效的评论,答案是仅链接(我的意思是答案更多的只是相关信息而不是实际答案),我觉得我需要使它更广泛。所以我在 http://gcc.godbolt.org/ 中尝试了两个样本看看生成了什么程序集,因为我没有可访问的 Linux 机器。奇怪的是 gcc 4.9 不合并字符串(或者我的汇编知识完全错误),所以问题是 - 它是否特定于您的工具链或者解析工具可能失败?见下图:
当然,如果我对程序集的理解是错误的,.LC1
和 .LC3
仍然可以在 .rodata
部分重叠,那么这并不能证明什么,但至少有人会纠正我,我会意识到这一点。
关于c++ - 与 GCC 共享不一致的字符串文字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31450680/