Files
CPlusPlusThings/site_extras/cpp-things-cpp-string-abi-compatibility.md
light-city dfe1c933b3 docs: address community issue feedback (#5 #338 #142 #246 #136 #303)
- const README: rewrite the space-saving claim per issue #5 follow-ups
  (constant-expression const vs #define immediates; which const qualify
  as constant expressions)
- const README: fix the class-section diagnosis per issue #338 (overload
  resolution picks the const overload; the restriction only surfaces
  once that overload is removed)
- sizeof README: virtual-inheritance result is compiler-dependent
  (GCC merges vbptr+vfptr -> 16, MSVC keeps them separate -> 32) #246
- static README: new section on internal linkage / access restriction
  with anonymous-namespace comparison #142
- 10-day practice: full problem list table + fixed day links #136
- new design_pattern/singleton/singleton_default.hpp: reusable
  thread-safe CRTP singleton template, compile+concurrency tested #303
2026-10-13 19:23:54 +08:00

99 lines
3.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
> 来自 [C++那些事网站](https://light-city.github.io/stories_things/cpp-things/cpp-string-abi-compatibility/) 的文章,由站点同步脚本导出。
# C++ string ABI 兼容性
### 项目实战问题:避坑 C++ String ABI 兼容性问题
[TOC]
为什么很多人不喜欢C++ string,反而要自己造轮子呢?其中一个问题就是C++ string abi问题,你遇到过吗?
之前使用conan与跨平台库的时候发生了C++ string abi兼容问题,本节将会引入ABI的背景与编译器相关的内容,讲讲如何避免这个坑,如果你遇到过,欢迎留言~
#### 1. ABI 变更的背景
**GCC 5.1**之后加强了对 C++11 的支持,并引入了一些新特性。在这一版本中,libstdc++ 引入了新的库 ABI,更新了 `std::string` 和 `std::list` 的实现。这些变化符合 C++11 标准,后者禁止使用 Copy-On-Write 字符串,并要求链表能够跟踪其大小。
实际项目中在使用 Conan 时,开发者可以通过调整 `compiler.libcxx` 来选择使用的 ABI:
- **libstdc++**:使用旧 ABI。
- **libstdc++11**:使用新 ABI。
选择适当的 ABI 可以确保与其他依赖库的兼容性,特别是在使用不同版本的编译器或库时。
#### 2. 编译器的默认设置
在使用 GCC 进行编译时,如果没有显式地指定 `--with-default-libstdcxx-abi=gcc4-compatible`,则 GCC 默认使用新的 C++11 ABI。这意味着:
- 如果你的代码或依赖库是在旧 ABI 下编译的,那么当你尝试链接时,可能会遇到未定义的符号错误。
例如,编译以下代码时:
```cpp
// lib.cc
#include <string>
void foo(const std::string& s) {}
```
使用命令:
```bash
g++-14 -D_GLIBCXX_USE_CXX11_ABI=0 -c lib.cc
```
将生成符号 `__Z3fooRKSs`,这是旧 ABI 的格式。
然而,当你编译并链接另一个使用新 ABI 的文件时,可能会出现如下错误:
```bash
g++-14 main.cc lib.o
```
```
Undefined symbols for architecture x86_64:
"foo(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)", referenced from:
_main in ccbWGoYh.o
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status
```
#### 3. 解决方案
为了确保编译通过,有以下两种解决方案:
**方法 1: 手动指定 ABI**
在编译所有源文件时,确保手动添加 `-D_GLIBCXX_USE_CXX11_ABI=0` 来兼容旧的库,例如:
```bash
g++-14 -D_GLIBCXX_USE_CXX11_ABI=0 main.cc lib.o
```
**方法 2: 使用新的 ABI 编译所有文件**
如果你愿意使用新的 C++11 ABI,可以在编译库文件时使用 `-D_GLIBCXX_USE_CXX11_ABI=1`,这样两者符号就会匹配:
```bash
g++-14 -D_GLIBCXX_USE_CXX11_ABI=1 -c lib.cc
g++-14 main.cc lib.o
```
此时,链接时符号将会匹配,不再出现未定义符号的错误。
#### 4. 符号比较
通过 `nm` 命令查看不同 ABI 下的符号,可以直观地看到二者的差异:
```bash
g++-14 -D_GLIBCXX_USE_CXX11_ABI=0 -c lib.cc
nm lib.o | grep foo
# 输出: 0000000000000000 T __Z3fooRKSs
g++-14 -D_GLIBCXX_USE_CXX11_ABI=1 -c lib.cc
nm lib.o | grep foo
# 输出: 0000000000000000 T __Z3fooRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
```
#### 5. 小结
ABI是C++升级以及编译过程中遇到的一个非常大的坑,希望可以通过这篇文章讲明白这些内容。