关于c++中的编译宏_GLIBCXX_USE_CXX11_ABI

关于 _GLIBCXX_USE_CXX11_ABI

_GLIBCXX_USE_CXX11_ABIC++中的编译宏, 用来控制stringlist使用的版本。 该宏仅在GCC5.1及后续版本中有效。

stringlist的新版本符号是std::__cxx11::basic_stringstd::__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.oa.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.datas也被改变了, 说明ss1共享了内存。 -D_GLIBCXX_USE_CXX11_ABI=1s没改变,说明ss1没有共享内存。

参考:
string底层实现之COW
Dual ABI

你可能感兴趣的:(c++,开发语言)