外部"C"是否应附上C++职能的声明或定义?

  • 本文关键字:声明 定义 C++ 是否 外部 c++ c
  • 更新时间 :
  • 英文 :


我在一个 cpp 文件中看到了external "C" {...}包含几个函数的定义。

从 https://isocpp.org/wiki/faq/mixing-c-and-cpp,我想在 cpp 文件中使用extern "C"的目的是使附带的C++函数可用于 C 程序。

链接中的示例显示,extern "C"仅包含C++函数的声明,而不是其定义

只需声明C++函数 extern "C"(在您的C++代码中)并调用 它(来自您的 C 或 C++ 代码)。例如:

// C++ code:
extern "C" void f(int);
void f(int i)
{
// ...
}

我在开头提到的 cpp 文件看起来像:

// C++ code:
extern "C" {
void f(int i)
{
// ...
}
void g(int i)
{
// ...
}
}

extern "C"是否应附上C++职能的声明或定义? 如果是这样,为什么?

它应该将声明括在头文件中,并且只要使用 C++ 编译器编译翻译单元,并且只要声明未在那里看到,就应该包含定义。
在 C++ 代码中同时做这两件事永远不会错。

如果使用 c 编译器来编译函数定义,则没有必要(或者我应该更好地说是错误的语法,请参阅下面的注释)。

extern "C" {}范围控制将纯 C 符号链接用于内部的所有内容。否则,将应用c++ 名称重整


注意:

由于extern "C" {}这不是有效的 c 语法,因此要使其与 c 编译器一起使用,您需要在#ifdef中使用它:

MyHeader.h

#ifdef __cplusplus
extern "C" {
#endif
// ... c style function name declarations
void foo(int i);
#ifdef __cplusplus
} // extern "C"
#endif

extern "C" {}范围的使用实际上是双重的:


将C++代码导出为 C

如果上述内容是使用 c 编译器编译的,则显示为普通的 c 函数声明。如果使用 c++ 编译器编译,则extern关键字适用,并且 c++ 名称重整将被禁止。

关于定义,该函数可以在其定义中使用任何 c++ 功能:

extern "C" {
void foo(int x) {
std::vector v(x);
// ... blah, more c++ stuff
}
}

请注意,此处未包含声明。这可以用作一种技术,当您想要覆盖从库中公开的函数以进行弱链接时特别有用。

在包含MyHeader.h的情况下,可以省略extern "C" {}范围。


从C++导入 C 代码

如果在 c++ 编译器中看到上述声明,则再次禁止 c++ 名称重整,并且链接器将使用纯 c 函数符号名称解析对foo()的任何调用引用:

#include "MyHeader.h"
class MyClass {
public:
void bar(int y) {
// Use foo() as plain c function:
foo(y);
}
};

foo()函数实现是从使用 c 编译器创建的目标文件(或存档)提供的。

[dcl.link]/5:

除具有C++链接的函数外,没有 联动规格不得先于第一次联动 该函数的规范。可以在没有 显式链接规范之后的链接规范 明显;前面声明中明确指定的链接是 不受此类函数声明的影响。

就函数的语言链接而言,这两个版本都很好。重要的部分是函数的第一个声明必须具有extern "C"

最好包括两者。

为了确保当我们在C++中链接 C 代码时,该符号不会被破坏,我们使用外部"C"块。

每当将某些代码放入 extern "C" 块时,C++编译器都会确保函数名称未被篡改,即编译器生成一个名称不变的二进制文件,就像 C 编译器所做的那样。

重整 As C++ 支持函数重载,因此基本上可以有多个同名函数。因此,为了在生成目标代码时区分不同的函数 – 它通过添加有关参数的信息来更改名称。向函数名称添加附加信息的技术称为名称重整。

由于 C 不支持函数重载。所以我们在链接 C++ C 代码时使用 extern 'C' 块。

应将声明和定义都括起来。"C"和"C++"函数以不同的名称导出。要在目标文件中生成正确的"C"外部名称extern "C"需要在 cpp 中,否则函数将使用C++名称重整导出。您还需要将这些extern "C" {和相应的}包含在#ifdef __cplusplus中并#endif在头文件中,这将由 C 项目 #included 以避免 C 编译错误

在同一文档中,它显示了一个代码示例,该示例在声明中具有extern "C",但在定义中没有。

如果定义"看到"声明(即声明位于翻译单元中的定义之前),则无需extern "C"定义。但它不会受到伤害 - 编译器会默默忽略它。

以下是常见问题解答中给出的代码示例:

// This is C++ code
// Declare f(int,char,float) using extern "C":
extern "C" void f(int i, char c, float x);
// ...
// Define f(int,char,float) in some C++ module:
void f(int i, char c, float x)
{
// ...
}

如果出于任何原因决定不在定义之前包含声明,则必须提供extern "C"修饰符:

// This is C++ code
// Define f(int,char,float) in some C++ module:
extern "C" void f(int i, char c, float x)
{
// ...
}

但是,这违背了 C 和 C++ 的大多数样式指南。

最新更新