1. 背景
為了工作需要,在抽離一個開源庫組件的時候,編譯成功鏈接卻失敗,查找原因發(fā)現(xiàn)測試文件使用的是C++語言,而庫的組件使用的是C語言,具體原因記錄與此。
2. 現(xiàn)場
為了測試,寫了一個單獨的簡單案例:
新建win32
工程,建立三個文件,分別是test.c
、test.h
和main.cpp
。
main.cpp
#include "test.h"
int main()
{
test(1);
return 0;
}
test.h
#ifndef _TEST_H_
#define _TEST_H_
void test(int a);
#endif
test.c
#include "test.h"
void test(int a)
{
}
編譯運行:
3. 原因
編譯成功,鏈接失敗,很顯然代碼中已經(jīng)實現(xiàn)了test
函數(shù),為了查找原因,直接打開vs命令行工具查看一下編譯后的符號表都有什么。
進入Debug目錄,執(zhí)行dumpbin /SYMBOLS test.obj
。
答案很顯然,編譯test.c
生成的符號是_test
,而現(xiàn)在要找的是void __cdecl test(int)" (?test@@YAXH@Z)
,結(jié)果當(dāng)然是無法找到的。
為了進一步確認(rèn)答案,將test.c
改為test.cpp
,重新編譯,查看符號表。
對于C語言生成的符號表和C++語言生成的符號表差距很大,原因無非是C++支持了很多新的功能,原來的符號表生成規(guī)則已經(jīng)無法滿足。
例如:重載、多態(tài)等機制。
為了解決這個問題,C++語言引入了另一種語法來解決這個問題。
4. 結(jié)論
對于C語言編寫的程序來說,未來可能被C語言或者C++語言的用戶所使用,大部分解決的方法是:
#ifdef __cplusplus
extern "C" {
#endif
// ...
#ifdef __cplusplus
}
#endif
直接在C語言中使用extern "C"
會報語法錯誤,因為該語法是C++語法,對于C語言來說,聲明該接口是C語言編寫的顯然沒有任何意義,它的目標(biāo)是使用C++語言的用戶;而對于C++用戶,該聲明卻是必須的,因為C和C++語言編寫的函數(shù)的符號表生成結(jié)果是不一致的,除非你在編譯C文件的時候明確用C++編譯器,那就沒什么問題了。