1.c與c++編譯方式
(1)gcc和g++都可以編譯.c文件,也都可以編譯.cpp文件。g++和gcc是通過后綴名來辨別是c程序還是c++程序的(這一點與Linux辨別文件的方式不同,Linux是通過文件信息頭辨別文件的)。
(2)在gcc看來,.c文件會以c方式去編譯,.cpp文件則是以c++的方式去編譯,注意,gcc不會主動去鏈接c++用到庫stdc++,所以用gcc編譯cpp文件時需要手動指定鏈接選項-lstdc++。而對於g++,不管是.c還是.cpp文件,都是以c++方式去編譯。
(3)還需要注意,並不是說__cpluscplus 是g++編譯器才會定義的宏,確切的說,是只有以c++編譯的方式去編譯文件的宏才會定義的宏,這樣說來,gcc編譯.cpp文件、g++編譯.c、.cpp文件,這個 __cplusplus都會被編譯器定義。
2.c++調用c程序
假設c程序是之前寫好的具有價值的靜態庫,該庫是由add.o和sub.o編譯而成,而add.c和sub.c是由c語言寫的:
add.h和add.c
//add.h #ifndef __ADD_H__ #define __ADD_H__ int add(int, int); #endif /* __ADD_H__ */ //add.c #include "add.h" int add(int a, int b) { return a + b; } sub.h和sub.c //sub.h #ifndef __SUB_H__ #define __SUB_H__ int sub(int, int); #endif /* __SUB_H__ */ //sub.c #include <stdio.h> #include "sub.h" int sub(int a, int b) { printf("%d - %d = %d\n", a, b, a - b); return 0; }
將各自編譯成.o文件,並打包成靜態庫
$ gcc -c add.c $ gcc -c sub.c $ ar cqs libadd.a *.o
這樣就生成了libadd.a靜態庫。
若要編譯成動態庫,則
$ gcc -shared -fPIC *.o -o libadd.so
main.cpp是c++寫的,用g++編譯。
//main.cpp #include "add.h" #include "sub.h" #include <stdio.h> int main(void) { int c = add(1, 6); sub(8, 2); printf("c = %d\n", c); return 0; }
編譯:

報錯未定義的add和sub函數。
通過nm確實是可以看到add和sub標號的存在的:

原因在於,main.cpp是c++文件,用g++編譯器編譯時(gcc也是一樣的結果),會優先選擇cpp的編譯方式,也就是會用cpp的編譯方式去編譯add()、sub()函數。然而,它們是.c文件,用的是c語言的方式去編譯的,所以出現如上問題。注意,cpp編譯器是兼容c語言的編譯方式的,所以在編譯cpp文件的時候,調用到.c文件的函數的地方時,需要用extern “C”指定用c語言的方式去編譯它:
//使得add.h、sub.h里面的代碼用c語言的方式去編譯
extern "C"{ #include "add.h" #include "sub.h" } #include <stdio.h> int main(void) { int c = add(1, 6); printf("c = %d\n", c); return 0; }
編譯運行

特別注意extern “C”是c++方式編譯才認識的關鍵字。
3. c語言調用c++程序
c語言用c方式編譯,c++程序用c++方式,要使得c語言能調用c++程序無非有2種方法(c++調用c也是一樣)
(1) c語言程序用c++方式編譯
既然是c語言調用c++程序,肯定是要采取c++方式編譯,所以覺得這個沒什么意義。操作很簡單,用g++方式編譯c程序即可,注意,g++會對語法、類型等更為嚴格的檢查。
(2) c++程序用c語言方式編譯
a. c方式編譯和c++方式編譯,其差異就在於符號表標識符。同一個函數名,在c方式編譯的其函數名跟編譯前的函數一致,c++方式編譯的則是以函數名結合參數作為編譯后的函數名。要確保文件以.c方式編譯,可以利用__cplusplus,這個宏在c++編譯的方式才會定義的宏,結合之前的extern C用法如下:
#ifdef __cplusplus extern "C"{ #endif /* __cplusplus */ //用c方式編譯的代碼 #ifdef __cplusplus } #endif /* __cplusplus */
這樣,對於一份.c文件,采用gcc編譯時候沒有定義__cplusplus,宏判斷不起作用,且自是用c語言的方式編譯,采用g++編譯定義了_cplusplus,經過上面宏判斷,所以還是會以c語言的方式編譯。注意,extern “C”是g++才具有的關鍵字,gcc並沒有,所以如果用gcc編譯而不加以宏判斷直接使用extern “C”那么就會出現語法錯誤。
用c方式去編譯c++文件,還要注意重載函數。c方式編譯的c++文件決定不能出現重載函數。嘗試extern “C”中出現重載函數:
#ifdef __cplusplus extern "C"{ #endif /* __cplusplus */ int func(int a, int b){ return a + b; } void func(const char* str){ printf("str = %s\n", str); } #ifdef __cplusplus } #endif /* __cplusplus */ int main(void) { func("hello"); return 0; }

提示找不到func函數。在c語言中肯定不能出現同名函數,不然編譯器怎么知道它要調用的是哪一個。去除extern “C”關鍵字,也就是使其采用c++方式編譯,編譯結果:

編譯通過。通過nm命令可以查看可執行程序的符號表:

可見c++編譯方式會將重載函數名結合參數形成唯一的函數名。但是c方式編譯的可執行文件卻並非如此,函數名經過編譯后的符號還是之前的函數名,所以出現找不到調用函數的現象。
b. c程序要調用c++寫的程序,涉及到的可能有:c程序調用c++的普通函數,c程序調用c++的重載函數,c程序調用c++的成員函數(包括虛函數)。c程序自然是采用c的方式去編譯的,即是采用gcc編譯器,然而c++是采用c++方式編譯,所以要強制將c++代碼以c的方式去編譯。
(1) c程序調用c++的普通函數
add.h和add.cpp //add.h #ifndef _ADD_H_ #define _ADD_H_ int add(int, int); #endif /* _ADD_H_ */ //add.cpp #include <iostream> extern "C" { //以c的方式去編譯 int add(int a, int b) { std::cout<<"a + b = "<< a + b << std::endl; return 0; } }
注意不能在聲明add函數的add.h中指定以c的方式去編譯,因為add.h是要被main.c文件包含的,c方式編譯時並不能認得extern “C”關鍵字。
main.c //main.c #include <stdio.h> #include "add.h" int main(void) { add(4, 9); return 0; }
編譯運行:

因為add.cpp用到標准c++庫,所以要手動鏈接該庫。
(2)c調用c++的重載函數
前面已經知道,在extern “C”中是不允許出現重載函數的,因為c方式下的程序並不支持重載函數,所以需要對重載函數進行接口封裝。使用extern “C”是要告訴編譯器按照c的方式來編譯封裝接口,接口里面的函數還是按照c++的語法和c++方式編譯。
add.h和add.cpp //add.h #ifndef _ADD_H_ #define _ADD_H_ int add_ii(int, int); int add_c(char); #endif /* _ADD_H_ */
上面兩個函數是供c程序調用的,自然需要用c方式編譯。而這兩個函數的實現體可以去調用c++的重載函數,這就完美契合了。
//add.cpp #include <iostream> int add(int a, int b) { std::cout<< "a + b = " << a + b << std::endl; return 0; } int add(char c) { std::cout << "c = " << c << std::endl; } extern "C" int add_ii(int a, int b) //供c程序調用,用c方式編譯 { add(a, b); } extern "C" int add_c(char c) { add(c); }
main.cpp
//main.cpp #include <stdio.h> #include "add.h" int main(void) { add_ii(4, 9); add_c('d'); return 0; }
編譯運行:

---------------------
作者:echo_bright_
來源:CSDN
原文:https://blog.csdn.net/qq_29344757/article/details/73332501
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!
