5

我知道怎么用extern "C",但是什么时候必须用呢?

extern "C"告诉 C++ 编译器不要对大括号内的代码执行任何名称修改。这允许您从 C++ 中调用 C 函数。

例如:

#include <string.h>

int main()
{
    char s[] = "Hello";
    char d[6];

    strcpy_s(d, s);
}

虽然这在 VC++ 上编译得很好。但有时这会写成:

extern "C" {   
#include <string.h>  
}

我不明白这一点。你能举一个真实的例子extern "C"吗?

4

6 回答 6

7

您用于extern "C"防止在头文件和您的 C++ 目标文件中对已编译但未进行重整的库或对象进行名称重整。

例如,假设您有一个widget使用 C 编译器编译的库,因此其发布的接口是未损坏的。

如果您将头文件按原样包含在代码中,它将假定名称损坏,并且您将告诉链接器查找这些损坏的版本。

但是,由于您会要求类似的东西function@intarray_float_charptr并且widget图书馆只会发布function,所以您会遇到问题。

但是,如果您将其包含在:

extern "C" {
    #include "widget.h"
}

您的编译器会知道它应该尝试使用function未损坏的版本。

这就是为什么在旨在包含在 C _or C++ 程序中的 C 内容的头文件中,您会看到如下内容:

#ifdef __cplusplus
    extern "C" {
#endif

// Everything here works for both C and C++ compilers.

#ifdef __cplusplus
    }
#endif

如果您使用 C 编译器包含此内容,则这些#ifdef行将导致extern "C"内容消失。对于 C++ 编译器(在哪里__cplusplus定义),一切都不会被破坏。

于 2011-11-03T14:05:09.550 回答
4

extern "C"从库中导出函数时的一种非常常见的用法。如果您不禁用 C++ 名称修饰,否则您的库的客户端很难命名您的函数。同样,在另一个方向上,当您导入已通过 C 链接导出的函数时。

于 2011-11-03T14:04:02.067 回答
4

这是一个具体的例子,说明事情会在哪里中断并需要extern "C"修复。

module.h

int f(int arg);

module.c

int f(int arg) {
  return arg + 1;
}

main.cpp

#include "module.h"

int main() {
  f(42);
}

由于我混合使用 C 和 C++,这不会链接(在两个目标文件中,只有一个会知道f它的 C++ 重命名名称)。

解决此问题的最简单方法可能是使头文件与 C 和 C++ 兼容:

module.h

#ifdef __cplusplus
  extern "C" {
#endif

int f(int arg);

#ifdef __cplusplus
  }
#endif
于 2011-11-03T14:11:21.280 回答
1

当您链接用 C 编写的库时,extern告诉编译器不要修饰名称,以便链接器可以找到函数。在 C++ 中,函数名称等具有链接器的信息,例如名称中包含的参数类型和大小。

于 2011-11-03T14:05:58.193 回答
1

如果您正在生成一个二进制库 A,它公开了您想从二进制 B 调用的函数。

假设 A 是 A.dll,B 是 B.exe,而您在 Windows 系统上。

C++ 没有描述二进制布局,使得 B 知道如何调用 A。通常,这个问题可以通过使用相同的编译器来生成 A 和 B 来解决。如果您想要更通用的解决方案,请使用 extern 关键字。这以 C 方式公开了函数。C 确实描述了一种二进制格式,以便来自不同编译器的不同二进制文件可以相互通信。

见: http: //en.wikipedia.org/wiki/Application_binary_interface http://en.wikipedia.org/wiki/Name_mangling#Name_mangling_in_C.2B.2B

于 2011-11-03T14:10:43.760 回答
1

如果在您的 C++ 代码中,您#include有一个外部库的标头(用 C 编码),并且如果没有声明其中的函数,extern "C"它们将不起作用(您将在链接时获得未定义的引用)。

但是现在,编写 C 库并为您提供头文件的人往往知道这一点,并且经常将其extern "C"放在他们的头文件中(适当地用#ifdef __cplusplus.

也许更好的理解方法是使用(假设您有一个 Linux 系统)该nm实用程序向您显示在库或可执行文件中使用的(未损坏的)名称。

于 2011-11-03T14:11:02.240 回答