基于this question我理解了将C库与C ++代码链接起来的构造的目的。现在假设如下:
我有一个用C ++编译器编译的'.so'共享库。标题有一个'typedef stuct'和许多函数声明。如果标题包含extern“C”声明......
#ifdef __cplusplus
extern "C"
{
#endif
// typedef struct ...;
// function decls
#ifdef __cplusplus
}
#endif
......效果如何?具体来说,我想知道该声明是否有任何有害的副作用,因为共享库被编译为C ++,而不是C。
在这种情况下,是否有任何理由要使用extern“C”声明?
答案 0 :(得分:12)
这很重要,因此编译器不会命名mangle。 C ++使用名称修改来区分具有运算符重载的函数。
对二进制文件运行“/ usr / bin / nm”以查看C ++对函数名称的作用: _ZSt8_DestroyIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEiEvT_S7_SaIT0_E
extern“C”可以防止名称损坏。
答案 1 :(得分:4)
编译C ++时,方法名称会更改(修改) - 并且您将无法从使用C的其他dll / exe调用该方法。
为了保留类和方法名称,您需要将它们编译为“C”而不会出现名称错误。
该库仍然是一个C ++库,但它将一些声明(extern“c”块中的声明)公开为C方法。
答案 2 :(得分:3)
#ifdef
保护extern
声明是告诉C链接器符号具有C(未拼写)符号表条目。 #ifdef
确保C编译器编译的代码单元(文件)没有任何影响。
答案 3 :(得分:0)
使用extern "C"
对C ++ API的一个不利之处在于它会阻止您使用函数重载:
extern "C"
{
// ILLEGAL - C linkage does not support function overloading
void foo(int x);
void foo(const char *str);
}
答案 4 :(得分:0)
示例中的#ifdef
表示只有C ++编译器会看到extern
包装头文件,这意味着它将生成非损坏的名称。 C编译器没有看到extern
(它不会理解),但总是产生非损坏的名称。
这意味着C和C ++编译器将在其目标文件中生成相同的符号,因此无论哪个编译器为声明的函数生成目标代码,所有目标文件都将成功链接,因为符号具有相同的链接和相同的名称。
静态链接或与共享库链接不应有任何影响。