目次
1 背景
C言語とC++言語はプロジェクト開発でよく使われる言語ですが、開発過程でC++プログラムからCプログラムを呼び出す必要がある場合がよくあります。プロジェクトコードがC言語で書かれており、使用するコードテストフレームワークがC++で書かれている場合、Cプロジェクトコードをテストするために、Cコードで書かれた関数をC++コードで呼び出すのは当然です。
C言語で書かれた関数をC++コードで呼び出す場合、C言語とC++言語で生成される関数シンボルが異なるため、シンボルが見つからないことが最大の問題です。
2例
たとえば、foo.c ファイルのコードは次のとおりです。
int foo(int x, int y) {
return x + y;
}
foo.h のコードは次のとおりです。
int foo(int x, int y);
gcc ツールを使用して、foo.o ファイルをコンパイルおよび生成します。
parallels@ubuntu-linux-20-04-desktop:~/leecode2/ar$ gcc -c foo.c
parallels@ubuntu-linux-20-04-desktop:~/leecode2/ar$ ll
total 20
drwxrwxr-x 2 parallels parallels 4096 May 16 19:49 ./
drwxrwxr-x 13 parallels parallels 4096 May 16 19:45 ../
-rw-rw-r-- 1 parallels parallels 44 May 16 19:46 foo.c
-rw-rw-r-- 1 parallels parallels 22 May 16 19:47 foo.h
-rw-rw-r-- 1 parallels parallels 1296 May 16 19:49 foo.o
次に、ar ツールを使用してスタティック ライブラリを生成します。
parallels@ubuntu-linux-20-04-desktop:~/leecode2/ar$ ar -crv libfoo.a foo.o
a - foo.o
parallels@ubuntu-linux-20-04-desktop:~/leecode2/ar$ ll
total 24
drwxrwxr-x 2 parallels parallels 4096 May 16 19:51 ./
drwxrwxr-x 13 parallels parallels 4096 May 16 19:45 ../
-rw-rw-r-- 1 parallels parallels 44 May 16 19:46 foo.c
-rw-rw-r-- 1 parallels parallels 22 May 16 19:47 foo.h
-rw-rw-r-- 1 parallels parallels 1296 May 16 19:49 foo.o
-rw-rw-r-- 1 parallels parallels 1436 May 16 19:51 libfoo.a
test.cpp ファイルを書く
#include "foo.h"
int main() {
int ret = foo(10, 20);
return 0;
}
静的リンクに gcc ツールを使用すると、この時点で未定義シンボルの問題が発生します。
parallels@ubuntu-linux-20-04-desktop:~/leecode2/ar$ gcc test.cpp -L. -lfoo -o test
/usr/bin/ld: /tmp/cc96XOXw.o: in function `main':
test.cpp:(.text+0x10): undefined reference to `foo(int, int)'
collect2: error: ld returned 1 exit status
解決策は、ヘッダー ファイルをインクルードするときに extern "C" を使用し、test.cpp ファイルを次のように変更することです。
extern "C" {
#include "foo.h"
}
int main() {
int ret = foo(10, 20);
return 0;
}
次に、gcc ツールを使用して正常にリンクします。extern "C" はコンパイラに C 言語を使用してコンパイルするように指示するため、未定義シンボルの問題を解決できます。
parallels@ubuntu-linux-20-04-desktop:~/leecode2/ar$ gcc test.cpp -L. -lfoo -o test
parallels@ubuntu-linux-20-04-desktop:~/leecode2/ar$ ll
total 40
drwxrwxr-x 2 parallels parallels 4096 May 16 19:54 ./
drwxrwxr-x 13 parallels parallels 4096 May 16 19:45 ../
-rw-rw-r-- 1 parallels parallels 44 May 16 19:46 foo.c
-rw-rw-r-- 1 parallels parallels 22 May 16 19:47 foo.h
-rw-rw-r-- 1 parallels parallels 1296 May 16 19:49 foo.o
-rw-rw-r-- 1 parallels parallels 1436 May 16 19:51 libfoo.a
-rwxrwxr-x 1 parallels parallels 9280 May 16 19:54 test*
-rw-rw-r-- 1 parallels parallels 93 May 16 19:54 test.cpp
もちろん、foo.h ヘッダー ファイルを変更して、ヘッダー ファイルを次のように変更することもできます。
#ifndef _FOO_H_
#define _FOO_H_
#ifdef _cplusplus
extern "C" {
#endif
int foo(int x, int y);
#ifdef _cplusplus
}
#endif
#endif
次のコマンドでコンパイルします。
parallels@ubuntu-linux-20-04-desktop:~/leecode2/ar$ gcc test.cpp -L. -lfoo -D _cplusplus -o test
parallels@ubuntu-linux-20-04-desktop:~/leecode2/ar$ ll
total 40
drwxrwxr-x 2 parallels parallels 4096 May 16 21:39 ./
drwxrwxr-x 13 parallels parallels 4096 May 16 19:45 ../
-rw-rw-r-- 1 parallels parallels 44 May 16 19:46 foo.c
-rw-rw-r-- 1 parallels parallels 130 May 16 21:32 foo.h
-rw-rw-r-- 1 parallels parallels 1296 May 16 19:49 foo.o
-rw-rw-r-- 1 parallels parallels 1436 May 16 19:51 libfoo.a
-rwxrwxr-x 1 parallels parallels 9280 May 16 21:39 test*
-rw-rw-r-- 1 parallels parallels 74 May 16 21:32 test.cpp
parallels@ubuntu-linux-20-04-desktop:~/leecode2/ar$
3 C 言語プログラム呼び出し C++ コード ライブラリ
逆に、C 言語プログラムはどのように C++ コード ライブラリを呼び出すのでしょうか? 実際には、C++ コード ライブラリに中間層を追加する必要があります. C コードで使用されるインターフェイスのセットを C++ コード ライブラリに提供するには、これらのインターフェイスを C 言語でコンパイルする必要があります。