C++ uses C library example

C compiler 編出來的 object file 可以跟 C++ compiler 編出來的 object file link 在一起。

假設 Linux 環境下有一個 object file foo.o 是 C compiler 編出來的,可以將 foo.o 看作一 C library,而 main.cpp 是由 C++ 實作並且使用 foo.o 裡的 function,因此 main.cpp 會 include 內含 function declaration 的 foo.h。C++ compiler 在一般狀況下會將 foo.h 內的 function 當作 C++ function 以 C++ 的規則處理。

由於 foo.o 是 C compiler 編出來的,其對 function 的處理方式不像 C++ 會額外加修飾,使得 link 時 main.ofoo.o 中 symbol 對不起來而產生 undefined reference 錯誤。在 foo.h 中加上 extern "C" 是告訴 C++ compiler 要把這段 function declaration 當作 C function 處理,也就是不做 name decoration,之後 link symbol 才對得起來。實例如下:

foo.h
1
2
3
4
5
6
7
8
9
10
// foo.h
#ifdef __cplusplus
extern "C" {
#endif

void foo();

#ifdef __cplusplus
}
#endif
foo.c
1
2
3
4
5
6
7
8
// foo.c
#include <stdio.h>
#include "foo.h"

void foo()
{
printf("C foo()!\n");
}
main.cpp
1
2
3
4
5
6
7
8
9
10
// main.cpp
#include <iostream>
#include "foo.h"

int main()
{
std::cout << "C++ main" << endl;
foo();
return 0;
}

foo.o 的 symbol:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
> gcc -c foo.c
> readelf -s foo.o

Symbol table '.symtab' contains 11 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 FILE LOCAL DEFAULT ABS foo.c
2: 00000000 0 SECTION LOCAL DEFAULT 1
3: 00000000 0 SECTION LOCAL DEFAULT 3
4: 00000000 0 SECTION LOCAL DEFAULT 4
5: 00000000 0 SECTION LOCAL DEFAULT 5
6: 00000000 0 SECTION LOCAL DEFAULT 7
7: 00000000 0 SECTION LOCAL DEFAULT 8
8: 00000000 0 SECTION LOCAL DEFAULT 6
9: 00000000 20 FUNC GLOBAL DEFAULT 1 foo
10: 00000000 0 NOTYPE GLOBAL DEFAULT UND puts

一般狀況的 main.o symbol(重點在 18):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
> g++ -c main.cpp
> readelf -s main.o

Symbol table '.symtab' contains 23 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 FILE LOCAL DEFAULT ABS main.cpp
2: 00000000 0 SECTION LOCAL DEFAULT 1
3: 00000000 0 SECTION LOCAL DEFAULT 3
4: 00000000 0 SECTION LOCAL DEFAULT 4
5: 00000000 1 OBJECT LOCAL DEFAULT 4 _ZStL8__ioinit
6: 00000000 0 SECTION LOCAL DEFAULT 5
7: 00000039 64 FUNC LOCAL DEFAULT 1 _Z41__static_initializati
8: 00000079 28 FUNC LOCAL DEFAULT 1 _GLOBAL__sub_I_main
9: 00000000 0 SECTION LOCAL DEFAULT 6
10: 00000000 0 SECTION LOCAL DEFAULT 9
11: 00000000 0 SECTION LOCAL DEFAULT 10
12: 00000000 0 SECTION LOCAL DEFAULT 8
13: 00000000 57 FUNC GLOBAL DEFAULT 1 main
14: 00000000 0 NOTYPE GLOBAL DEFAULT UND _ZSt4cout
15: 00000000 0 NOTYPE GLOBAL DEFAULT UND _ZStlsISt11char_traitsIcE
16: 00000000 0 NOTYPE GLOBAL DEFAULT UND _ZSt4endlIcSt11char_trait
17: 00000000 0 NOTYPE GLOBAL DEFAULT UND _ZNSolsEPFRSoS_E
18: 00000000 0 NOTYPE GLOBAL DEFAULT UND _Z3foov
19: 00000000 0 NOTYPE GLOBAL DEFAULT UND _ZNSt8ios_base4InitC1Ev
20: 00000000 0 NOTYPE GLOBAL DEFAULT UND _ZNSt8ios_base4InitD1Ev
21: 00000000 0 NOTYPE GLOBAL DEFAULT UND __dso_handle
22: 00000000 0 NOTYPE GLOBAL DEFAULT UND __cxa_atexit

foo.hextern "C"main.o symbol:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
>readelf -s main.o

Symbol table '.symtab' contains 23 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 FILE LOCAL DEFAULT ABS main.cpp
2: 00000000 0 SECTION LOCAL DEFAULT 1
3: 00000000 0 SECTION LOCAL DEFAULT 3
4: 00000000 0 SECTION LOCAL DEFAULT 4
5: 00000000 1 OBJECT LOCAL DEFAULT 4 _ZStL8__ioinit
6: 00000000 0 SECTION LOCAL DEFAULT 5
7: 00000039 64 FUNC LOCAL DEFAULT 1 _Z41__static_initializati
8: 00000079 28 FUNC LOCAL DEFAULT 1 _GLOBAL__sub_I_main
9: 00000000 0 SECTION LOCAL DEFAULT 6
10: 00000000 0 SECTION LOCAL DEFAULT 9
11: 00000000 0 SECTION LOCAL DEFAULT 10
12: 00000000 0 SECTION LOCAL DEFAULT 8
13: 00000000 57 FUNC GLOBAL DEFAULT 1 main
14: 00000000 0 NOTYPE GLOBAL DEFAULT UND _ZSt4cout
15: 00000000 0 NOTYPE GLOBAL DEFAULT UND _ZStlsISt11char_traitsIcE
16: 00000000 0 NOTYPE GLOBAL DEFAULT UND _ZSt4endlIcSt11char_trait
17: 00000000 0 NOTYPE GLOBAL DEFAULT UND _ZNSolsEPFRSoS_E
18: 00000000 0 NOTYPE GLOBAL DEFAULT UND foo
19: 00000000 0 NOTYPE GLOBAL DEFAULT UND _ZNSt8ios_base4InitC1Ev
20: 00000000 0 NOTYPE GLOBAL DEFAULT UND _ZNSt8ios_base4InitD1Ev
21: 00000000 0 NOTYPE GLOBAL DEFAULT UND __dso_handle
22: 00000000 0 NOTYPE GLOBAL DEFAULT UND __cxa_atexit