【发布时间】:2010-09-16 17:07:50
【问题描述】:
我们知道我们可以直接在c++中使用c函数,那么什么时候需要extern "C"呢?
【问题讨论】:
我们知道我们可以直接在c++中使用c函数,那么什么时候需要extern "C"呢?
【问题讨论】:
如果您的函数是在 .c 文件中实现的,则 .cpp 文件将需要 extern "C" 引用,否则它们会引用一个损坏的 C++ 样式的函数名,并且链接会失败。
从 DLL 中导出函数也很方便,这样它们就可以以未损坏的名称导出。
【讨论】:
当C++ 函数必须由C 代码而不是C++ 代码调用时,这是必要的。
基本上,当您希望您的 C++ 库向后兼容时。
【讨论】:
C,请不要将C++ 添加到其中:将其转换为C++,如果需要,将C 添加到C++ 项目。 或者(更好的恕我直言)将其保留在 C 中并完全避免 C++。
extern "C" 有两种截然不同的用途。一种是在 C++ 中定义一个应该能够从 C 调用的函数。即,你正在用 C++ 编写代码,但它需要与 C 代码交互。在这种情况下,您将函数定义为extern "C":
extern "C" {
int c_callable_func1() {}
int c_callable_func2() {}
}
当您这样做时,这些函数的接口必须遵循与 C 中几乎相同的规则(例如,您不能重载函数或对任何参数使用默认值)。
另一种(相当常见的)情况是您有用 C 编写的代码,您希望能够从 C++ 调用。在这种情况下,函数定义 与以前完全相同,但需要将函数声明/原型化为extern "C"。在典型情况下,您希望在 C 或 C++ 文件中使用可以是 #included 的单个标头,因此结构如下所示:
// myheader.h
#ifndef MY_HEADER_H_INCLUDED_
#define MY_HEADER_H_INCLUDED_
#ifdef __cplusplus
extern "C" {
#endif
int func1(void);
void func2(int);
#ifdef __cplusplus
}
#endif
#endif
因此,C++ 编译器会看到被extern "C" 块包围的函数声明(和typedefs 等),而C 编译器会看到原型,而不是被它无法识别的东西包围。
在第一种情况下(可从 C 调用的 C++ 函数),您通常会以大致相同的方式构建标头,因此您也可以在必要时从 C++ 调用这些函数(但在接口处,您仍然会丢失所有额外的功能类似 C++ 的函数重载)。
【讨论】:
如您所知,c++ 支持函数重载,它使用不同的参数多次定义相同的函数或方法。为此,编译器必须为每个符号添加一些符号...例如,编译器将在以下声明中更改函数名称 foo 来自
void foo(int f,char c);
到
foo@i&c
不幸的是,C 不支持这一点。编译后所有函数名称保持不变。所以,要从 c 中调用 c++ 函数,你必须知道修改后的确切名称,我认为这很难,而且从一个编译器到另一个编译器是不同的。
要解决这个问题并能够从 c 调用 c++ 函数并阻止编译器更改您必须使用此关键字的名称,例如
extern "C" {
void foo(int f,char c);
}
就是这样!!!
【讨论】:
extern "C" 限定符的标头,则 c++编译器将破坏符号。然后在链接阶段,它将尝试定位损坏的符号,但会失败,因为 c 编译器在编译 C 代码时没有损坏名称。
因为 C 和 C++ 编译器生成的函数签名不同 - 即使在使用 C++ 时,这也会为 C 函数设置 C 约定。
【讨论】: