extern "C"用于明確告訴C++編譯器放棄名字粉碎的工作機制,使其保留原始的符號名稱。
純粹的C庫
即使你提供的是一個純粹的C庫,也必須正確使用extern "C",因為你的C函數(shù)可能被C++的程序所使用。
// oss/include/oss_memery.h
#ifndef HF0916DFB_1CD1_4811_B82B_9B8EB1A007D8
#define HF0916DFB_1CD1_4811_B82B_9B8EB1A007D8
#include "oss_common.h"
#ifdef __cplusplus
extern "C" {
#endif
void* oss_alloc(size_t);
void oss_free(void*);
#ifdef __cplusplus
}
#endif
#endif
如果在C庫中遺漏extern "C"的聲明,則C++程序員為了引用該庫的符號時,唯一的選擇就是使用extern "C"包含整個頭文件,而這種模式恰好是一種反模式。因此,C程序員定義對外公開的頭文件時,需要特別的注意這件事情。
#ifdef __cplusplus
extern "C" {
#endif
#include "oss_memory.h"
#ifdef __cplusplus
}
#endif
反模式
在extern "C"中包含頭文件,是一種典型的反模式。如下示例代碼,oss_common.h置于extern "C"之中,將導(dǎo)致其內(nèi)部或間接通過#include引入的符號都置于extern "C"的作用域之內(nèi);更為嚴重的是,如果oss_common.h也使用了extern "C",將導(dǎo)致嵌套的extern "C"語句,導(dǎo)致混亂的符號聲明。
// oss/include/oss_memery.h
#ifndef HF0916DFB_1CD1_4811_B82B_9B8EB1A007D8
#define HF0916DFB_1CD1_4811_B82B_9B8EB1A007D8
#ifdef __cplusplus
extern "C" {
#endif
#include "oss_common.h"
void* oss_alloc(size_t);
void oss_free(void*);
#ifdef __cplusplus
}
#endif
#endif
實用宏
可以定義一組實用宏,簡化extern "C"的作用域定義。在代碼的可讀性沒有下降的前提下,代碼從6行減少至2行。
// cub/base/externc.h
#ifdef __cplusplus
# define EXTERN_STDC_BEGIN extern "C" {
# define EXTERN_STDC_END }
#else
# define EXTERN_STDC_BEGIN
# define EXTERN_STDC_END
#endif
例如,上例使用宏定義后的代碼如下所示。
// oss/include/oss_memery.h
#ifndef HF0916DFB_1CD1_4811_B82B_9B8EB1A007D8
#define HF0916DFB_1CD1_4811_B82B_9B8EB1A007D8
#include "cub/base/externc.h"
#include "oss_common.h"
EXTERN_STDC_BEGIN
void* oss_alloc(size_t);
void oss_free(void*);
EXTERN_STDC_END
#endif