不同C++编译器下std::string的名称修饰差异原因咨询
为什么相近版本的GCC编译后std::string的修饰名称(mangled name)不同?
你观察到的差异确实和libstdc++的版本以及它的双ABI实现直接相关,具体原因如下:
1. libstdc++的双ABI背景
C11标准发布后,libstdc对std::string、std::list等容器做了重写优化——比如把std::string的写时复制(COW)实现改成了短字符串优化(SSO),性能提升明显。但为了兼容大量依赖旧实现的遗留代码,GCC引入了双ABI机制:
- 旧ABI(兼容模式):对应传统COW实现,修饰名称为
Ss - 新ABI(C++11+模式):对应新优化实现,修饰名称会包含
__cxx11命名空间,也就是你看到的NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
2. 不同系统的默认ABI选择
- CentOS 7:系统默认依赖旧版libstdc++,即便是使用devtoolset-7的GCC 7.3.1,为了保持系统整体兼容性,默认仍启用旧ABI,所以输出
Ss - Ubuntu 18.04:系统默认启用新ABI,因此同版本区间的GCC 7.5.0输出带
__cxx11的修饰名称
3. 手动切换ABI的方法
你可以通过编译选项强制指定要使用的ABI:
- 强制用旧ABI:添加编译标志
-D_GLIBCXX_USE_CXX11_ABI=0 - 强制用新ABI:添加编译标志
-D_GLIBCXX_USE_CXX11_ABI=1
比如在CentOS 7环境下编译时加上-D_GLIBCXX_USE_CXX11_ABI=1,就能得到和Ubuntu完全一致的修饰名称。
验证用代码示例
你的测试代码无需修改:
#include <cxxabi.h> #include <iostream> #include <string> int main(){ std::cout << typeid(std::string).name() << std::endl; return 0; }
强制新ABI的编译命令:
g++ --std=c++14 -D_GLIBCXX_USE_CXX11_ABI=1 test.cpp -o test
运行后会输出NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
内容的提问来源于stack exchange,提问作者Nicola Mori
相关产品推荐
相关产品推荐

