自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

C++ 竟然看不懂 C 代碼?揭秘背后不為人知的真相!

開發(fā)
我們有一位神通廣大的外交官 extern "C" ,它不僅精通雙方的"方言",還能讓這對(duì)歡喜冤家順利牽手,在項(xiàng)目中和諧共處。

想象一下,C++ 和 C 這對(duì)編程語(yǔ)言界的歡喜冤家,就像是來(lái)自不同星球的外星人,雖然都在用代碼交流,但總是雞同鴨講。別擔(dān)心!我們有一位神通廣大的外交官 extern "C" ,它不僅精通雙方的"方言",還能讓這對(duì)歡喜冤家順利牽手,在項(xiàng)目中和諧共處!

來(lái)看個(gè)有趣的小例子

想象一下,我們有一個(gè)超級(jí)簡(jiǎn)單的 C 語(yǔ)言文件,它就像是一個(gè)害羞的小朋友,只會(huì)做兩件事:加法和打招呼

// hello.h - 這是我們害羞的小朋友的自我介紹卡片 ??
int add(int a, int b);          // 會(huì)做加法的小能手 ?
void print_hello(void);         // 會(huì)說(shuō)"你好"的小可愛(ài) ??
// hello.c - 這是小朋友展示才藝的舞臺(tái) ??
#include "hello.h"

int add(int a, int b) {         // 1+1=2,就是這么簡(jiǎn)單! ??
    return a + b;
}

void print_hello(void) {        // 揮揮小手說(shuō)你好 ??
    printf("Hello from C!\n");
}

這個(gè)小朋友看起來(lái)很簡(jiǎn)單吧?但是當(dāng)它想和 C++ 這個(gè)"大哥哥"玩耍的時(shí)候,卻總是會(huì)遇到一些小麻煩。別著急,接下來(lái)我們就來(lái)看看如何讓他們變成好朋友!???

哎呀,出問(wèn)題啦!

當(dāng)我們天真地想讓 C++ 直接調(diào)用 C 的函數(shù)時(shí),編譯器就開始鬧脾氣了 ??:

// main.cpp - C++文件
#include "hello.h"

int main() {
    add(1, 2);      // 編譯器:這是啥?沒(méi)見(jiàn)過(guò)!??
    print_hello();   // 編譯器:完全不認(rèn)識(shí)啊!??
}

為啥會(huì)這樣呢?

原來(lái)啊,C++ 這個(gè)小機(jī)靈鬼為了支持函數(shù)重載這個(gè)炫酷功能 ?,會(huì)給每個(gè)函數(shù)起個(gè)獨(dú)特的"花名",這個(gè)過(guò)程叫做"名字修飾"(Name Mangling) ??。

就像給每個(gè)人起外號(hào)一樣!比如:

  • 把a(bǔ)dd(int, int) 悄悄改名叫_Z3addii ???
  • 把a(bǔ)dd(float, float) 改名叫_Z3addff ??
  • 把a(bǔ)dd(string, string) 改名叫_Z3addSsSs ??

而我們的 C 語(yǔ)言就像個(gè)耿直boy,叫add 就是add,從不玩花樣 ??。

這就好比:

  • C語(yǔ)言的世界:小明就叫"小明" ??
  • C++的世界:非要叫他"住在三樓打籃球特別溜還會(huì)彈吉他的小明" ????

這樣一來(lái):

  • C++編譯器看到_Z3addii 就知道:"啊,這是兩個(gè)整數(shù)相加的函數(shù)" ??
  • C編譯器看到這個(gè)名字就懵了:"這是啥外星文?" ??

所以當(dāng) C++ 想調(diào)用 C 函數(shù)時(shí),就會(huì)找不到對(duì)應(yīng)的函數(shù)名,因?yàn)樗谡規(guī)е陌姹荆?C 那邊只有樸實(shí)無(wú)華的原名 ??。這不就鬧別扭了嘛~ ??

舉個(gè)實(shí)際的例子

// C++ 代碼
void print(int x) { }           // 編譯后變成: _Z5printi
void print(double x) { }        // 編譯后變成: _Z5printd
void print(char* x) { }         // 編譯后變成: _Z5printPc

// C 代碼
void print(int x) { }           // 編譯后還是: print

這就是為什么我們需要 extern "C" 這個(gè)"翻譯官" ???,它能告訴 C++ 編譯器: "嘿,這個(gè)函數(shù)不要給它起花名了,就用原名吧!" ??

解決方案

要解決這個(gè)問(wèn)題,我們需要使用 extern "C" 來(lái)告訴 C++ 編譯器:"嘿,這些函數(shù)是 C 語(yǔ)言的,請(qǐng)用 C 的方式處理!" ???

正確的做法是這樣的:

// hello.h - 改良版 ???
#ifdef __cplusplus  // 判斷是否是C++編譯器 ??
extern "C" {        // 告訴C++編譯器:里面的東西用C的規(guī)則處理 ??
#endif

int add(int a, int b);          // 加法函數(shù) ?
void print_hello(void);         // 打招呼函數(shù) ??

#ifdef __cplusplus
}
// main.cpp - C++文件 ??
#include "hello.h"

int main() {
    int result = add(1, 2);     // 現(xiàn)在可以快樂(lè)地調(diào)用啦! ???
    print_hello();              // 完美運(yùn)行~ ????
    return 0;                   // 程序結(jié)束,返回0 ??
}

深入理解 extern "C" 的使用場(chǎng)景

1. 在 C++ 中調(diào)用 C 函數(shù)庫(kù)

很多優(yōu)秀的底層庫(kù)都是用 C 語(yǔ)言編寫的 ???,比如 SQLite ??、OpenSSL ?? 等。要在 C++ 項(xiàng)目中使用這些庫(kù),就需要 extern "C" ??:

// 使用 OpenSSL 的例子 ??
extern "C" {    // 打開 C 語(yǔ)言的大門 ??
    #include <openssl/ssl.h>    // 引入加密模塊 ???
    #include <openssl/err.h>    // 引入錯(cuò)誤處理 ??
}

// 現(xiàn)在可以開心地使用 OpenSSL 的函數(shù)啦~ ?? ? ??

2. 制作跨語(yǔ)言的動(dòng)態(tài)鏈接庫(kù)

如果你要制作一個(gè)既能被 C 又能被 C++ 調(diào)用的動(dòng)態(tài)鏈接庫(kù),extern "C" 是必不可少的 ??:

// mylib.h ??
#ifdef __cplusplus
extern "C" {  // 打開魔法門 ?
#endif

// 這些函數(shù)可以被 C/C++ 同時(shí)調(diào)用 ??
__declspec(dllexport) int calculate(int x, int y);      // 計(jì)算功能 ??
__declspec(dllexport) void process_data(const char* data);  // 數(shù)據(jù)處理 ??

#ifdef __cplusplus
}  // 關(guān)閉魔法門 ??
#endif

3. 處理函數(shù)指針

在涉及回調(diào)函數(shù)時(shí),extern "C" 特別重要:

// 錯(cuò)誤示范 ?
typedef void (*Callback)(int);  // C++ 風(fēng)格的函數(shù)指針

// 正確示范 ?
extern "C" {
    typedef void (*Callback)(int);  // 可以在 C/C++ 間通用的函數(shù)指針
}

注意事項(xiàng) - 寫好代碼的小錦囊

  • 不支持重載 - C語(yǔ)言的單純世界:
extern "C" {
    void print(int x);     // 小可愛(ài),這樣寫沒(méi)問(wèn)題哦~ ? ?? 
    void print(double x);  // 哎呀!C語(yǔ)言可不認(rèn)識(shí)重載這個(gè)高級(jí)貨 ? ?? 
    // C語(yǔ)言表示:我只想要一個(gè)print,不要整那么多花樣!??
}
  • 類成員函數(shù)不能用 extern "C" - C++獨(dú)有的小秘密:
class MyClass {
    extern "C" void method();  // 這樣寫編譯器會(huì)生氣的!? ?? 
    // C語(yǔ)言:類是啥?不認(rèn)識(shí)!我只認(rèn)識(shí)普通函數(shù)!??
};
  • 頭文件保護(hù) - 安全帽要戴好:
// 推薦的頭文件保護(hù)方式 - 讓代碼穿上安全盔甲 ?? ? 
#ifndef MY_HEADER_H    // 打開保護(hù)罩 ??
#define MY_HEADER_H    // 設(shè)置結(jié)界 ?

#ifdef __cplusplus     // 優(yōu)雅地詢問(wèn):這是C++編譯器嗎???
extern "C" {           // 是的話,請(qǐng)用C的方式理解下面的代碼 ??
#endif

// 你的精彩代碼在這里閃耀... ? ?? ??
// 可以放心大膽地寫聲明啦!??

#ifdef __cplusplus
}                      // 禮貌地說(shuō)再見(jiàn) ??
#endif

#endif // MY_HEADER_H  // 關(guān)閉結(jié)界 ??
  • 命名沖突的處理 - 給代碼起個(gè)好名字:
// 不好的做法 - 容易撞名字 ?
extern "C" {
    void init();    // 這名字太常見(jiàn)啦!很容易撞車的 ??
}

// 好的做法 - 加個(gè)獨(dú)特的前綴 ?
extern "C" {
    void mylib_init();    // 這樣就不怕和別人的init撞車?yán)??? ?
}
  • 混合編譯的小技巧 - 讓代碼更靈活:
// 聰明的條件編譯 ??
#if defined(__cplusplus) && defined(_WIN32)
extern "C" {
    __declspec(dllexport) void smart_function(); // Windows下的導(dǎo)出函數(shù) ??
}
#elif defined(__cplusplus) && defined(__linux__)
extern "C" {
    __attribute__((visibility("default"))) void smart_function(); // Linux下的導(dǎo)出函數(shù) ??
}
#endif

實(shí)用小貼士 - 進(jìn)階使用指南

  • 記得給所有 extern "C" 函數(shù)寫好文檔注釋
  • 避免在 extern "C" 函數(shù)中使用 C++ 特有的特性
  • 如果可能,盡量把 C 接口封裝成 C++ 類
  • 定期檢查跨語(yǔ)言接口的兼容性

?? 小提示:把 extern "C" 的聲明集中管理在一個(gè)專門的頭文件中,這樣維護(hù)起來(lái)更方便!

責(zé)任編輯:趙寧寧 來(lái)源: everystep
相關(guān)推薦

2025-01-07 07:20:00

C++代碼開發(fā)

2011-11-08 13:41:27

蘋果siri人工智能數(shù)據(jù)中心

2014-11-06 10:35:57

程序員

2010-08-05 11:14:12

Flex優(yōu)勢(shì)

2010-09-03 08:52:38

CSS

2011-04-29 10:47:18

虛擬化

2018-06-01 11:21:49

軟件開發(fā)真相

2019-06-05 12:49:07

云辦公

2025-01-24 09:10:00

2020-02-20 12:02:32

Python數(shù)據(jù)函數(shù)

2025-04-24 08:05:00

Linuxsort命令排序

2013-08-09 09:27:08

vCentervSphere

2010-04-19 16:09:22

Oracle控制文件

2013-07-16 13:59:15

空姐事件移動(dòng)市場(chǎng)華強(qiáng)北生態(tài)鏈

2011-11-15 10:25:56

IBMWindows

2014-08-18 10:44:31

斯諾登

2010-09-06 14:19:54

CSS

2011-11-14 10:06:16

IBM大型機(jī)支持Windows系統(tǒng)POWER7

2011-10-19 16:19:27

iOS 5蘋果

2012-11-30 14:13:01

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)