_GLIBCXX_USE_CXX11_ABI
是C++
中的编译宏, 用来控制string
及list
使用的版本。 该宏仅在GCC5.1
及后续版本中有效。
string
及list
的新版本符号是std::__cxx11::basic_string
及 std::__cxx11::list
。
举例如下:
// test.cc
#include
void test(std::string &s)
{
s = "Hello World";
return;
}
编译使用-D_GLIBCXX_USE_CXX11_ABI=1
[test]$ g++ -c -D_GLIBCXX_USE_CXX11_ABI=1 test.cc
[test]$ nm test.o
0000000000000000 T _Z4testRNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
U _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEaSEPKc
[test]$ c++filt _Z4testRNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
test(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)
[test]$
编译使用-D_GLIBCXX_USE_CXX11_ABI=0
[test]$ g++ -c -D_GLIBCXX_USE_CXX11_ABI=0 test.cc
[test]$ nm test.o
0000000000000000 T _Z4testRSs
U _ZNSsaSEPKc
[test]$ c++filt _Z4testRSs
test(std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)
[test]$
可以看到,-D_GLIBCXX_USE_CXX11_ABI=1
编译后的符号是 std::__cxx11::basic_string
,而-D_GLIBCXX_USE_CXX11_ABI=0
编译后的符号是 std::basic_string
。
string
版本不同引发的链接问题从上节中看到,不同版本的string
具有不同的符号。若程序使用了不同版本的库,则会有找不到符号的问题。举例如下:
// a.cc
#include
#include
using namespace std;
void a(string s)
{
cout << s << endl;
return ;
}
[test]$ g++ -c -D_GLIBCXX_USE_CXX11_ABI=1 a.cc
[test]$ nm a.o | grep " T "
0000000000000000 T _Z1aNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
[test]$ c++filt _Z1aNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
a(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)
[test]$
主程序:
// main.cc
#include
#include
using namespace std;
void a(string s);
int main()
{
a("12345");
return 0;
}
[test]$ g++ -c -D_GLIBCXX_USE_CXX11_ABI=0 main.cc
[test]$ nm main.o | grep _Z1aSs
U _Z1aSs
[test]$ c++filt _Z1aSs
a(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)
[test]$
可以看到,main.o
依赖的是std::basic_string
, 而a.o
中是std::__cxx11::basic_string
,将main.o
与a.o
链接起来会找不到符号,如下:
[test]$ g++ main.o a.o
main.o:在函数‘main’中:
main.cc:(.text+0x32):对‘a(std::string)’未定义的引用
collect2: 错误:ld 返回 1
[test]$
string
?在c++11
之前的版本,允许string Copy On Write
(即string COW
)功能,新的C++11
版本禁用了此项功能。在新的 C++11
中新增了__cxx11
这个命名空间以示区别。
简单来说, COW
功能是在string
对象赋值时, 两个string
对象共享内存, 只有在其中一个对象被修改时才会申请新的内存。
关于string COW
功能,看如下的代码:
// test.cc
#include
#include
using namespace std;
int main()
{
string s("str");
string s1 = s;
char *p = const_cast<char *>(s1.data());
p[2] = '\0';
cout << s << endl;
cout << s1 << endl;
return 0;
}
[test]$ g++ -D_GLIBCXX_USE_CXX11_ABI=1 test.cc
[test]$ ./a.out
str
st
[test]$ g++ -D_GLIBCXX_USE_CXX11_ABI=0 test.cc
[test]$ ./a.out
st
st
可以看到, -D_GLIBCXX_USE_CXX11_ABI=0
编译时修改s1.data
,s
也被改变了, 说明s
和s1
共享了内存。 -D_GLIBCXX_USE_CXX11_ABI=1
时 s
没改变,说明s
和s1
没有共享内存。
参考:
string底层实现之COW
Dual ABI