我在此代码中无法理解原因:
#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)。除了可能避免过长的链接器运行,尝试找到常见的后缀之外,这也没有多大意义。
答案 0 :(得分:0)
This论文对gcc和本主题进行了很好的研究。我个人不知道-fmerge-all-constants
,但您可以检查是否在两种情况下都使字符串重叠(因为该文件指出它不适用于O3
和Os
)。
修改强>
由于有一个有效的评论,答案只是链接(我的意思是答案更多只是一个相关的信息而不是一个实际的答案),我觉得我需要更广泛地做到这一点。因此,我在http://gcc.godbolt.org/中尝试了两个示例,以查看生成的程序集,因为我没有可访问的Linux机器。奇怪的是,gcc 4.9没有合并字符串(或者我的汇编知识完全错误),所以问题是 - 它可以特定于你的工具链,还是解析工具失败了?见下图:
当然,如果我对装配的理解是错误的,.LC1
和.LC3
仍然可以在.rodata
部分重叠,那么这不会证明什么,但至少有人会纠正我,我会意识到这一点。