c++ - 为什么 C++ 编译器内联字符串文字的一部分?
问题描述
考虑这个小的 C++ 代码片段:
#include <iostream>
#include <string>
int main() {
std::cout << std::string("This.String.Ends!") << std::endl;
}
此片段生成的程序集的一部分(使用 clang++ -O3 编译):
...
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_create(unsigned long&, unsigned long)
mov qword ptr [rsp + 16], rax
mov rcx, qword ptr [rsp + 8]
mov qword ptr [rsp + 32], rcx
movups xmm0, xmmword ptr [rip + .L.str]
movups xmmword ptr [rax], xmm0
mov byte ptr [rax + 16], 33 <--------- !!!!!!!!!
mov qword ptr [rsp + 24], rcx
mov rax, qword ptr [rsp + 16]
mov byte ptr [rax + rcx], 0
...
.L.str:
.asciz "This.String.Ends!"
即使字符串文字'!'
末尾有字符,生成的程序集也有一个额外的指令来显式添加它。问题:
- 这种优化叫什么?它有正式的名字吗?
- 我能够用 size 字符串重现这种行为
8x+y
。我可以想象从内存中仅获取一个字符比使用附加指令要昂贵。这里是这样吗?如果是这样,为什么不内联整个字符串(在这种情况下它很短)? - 我仍然可以保留
-O3
但避免这种特殊优化的不同方式是什么?从命中和试验中,我可以发现使用这些(与g++
)的组合会禁用它:-fno-tree-ccp -fno-tree-dominator-opts -fno-tree-forwprop -fno-tree-fre -fno-code-hoisting -fno-tree-pre -fno-tree-vrp
,但我猜每个人都会做更多我可能不想错过的事情。 - 如果编译器确实为最后一个字符生成指令,为什么还要将完整的字符串留在
.rodata
二进制部分,而不仅仅是开始的 16 个字节?不浪费空间吗?
我的用例:这种优化在编译+链接后的二进制文件中修补字符串文字会产生问题(替换'x'
为'y'
填充\0*(len('x')-len('y'))
,假设len('x') >= len('y')
)。我知道可能会有更多此类优化无法让我实现这一目标,但我只是想提供一些关于我如何解决这个问题的背景信息。
解决方案
推荐阅读
- logstash - 如何检查json字符串中的键值对以获取logstash中的消息字段
- html - 带有复选框选项的 React Dropdown Modal-ish - 按部分分隔
- javascript - 我的循环如何返回 100?我很困惑
- r - 下标越界,需要 SDM 帮助
- python - 实现 SSL 证书的 Python 套接字
- catboost - 将目标编码值传递给 CatBoost
- openjdk-11 - 使用 Cygwin 在 Windows 上从 openjdk 的源代码构建 jdk11
- amazon-web-services - 通过具有特定角色的 EKSCTL 创建 EKS 集群
- python - Ape 尝试制作密码生成器:“if 语句”和“try & except”函数太难了(Python)
- excel - 如何使用 IFNA,如果 NA 作为文本字符串加上顺序编号,则创建值