外部"C"是否应附上C++职能的声明或定义?
Shall external "C" enclose the declaration or definition of a C++ function?
我在一个 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++ 的大多数样式指南。
- 如何在C++中声明/定义相互依赖的模板?
- C++概念是否允许我的类在声明/定义中指定它满足某些概念?
- MSVC:无法识别的模板声明/定义(使用 Clang/GCC 编译)
- 我可以重用同一个模板来声明/定义多个东西吗(而不复制模板代码)
- C++-模板类中模板函数的单独声明/定义
- 在C 中使用继承时,请避免使用未缴纳的函数声明/定义
- C++模板能否确定所声明/定义的实例是否为常量
- 如何在程序中声明/定义一次并在两个类中使用映射列表
- LBNF,C函数声明/定义,减少冲突
- 声明/定义返回具有自动返回类型的 valarray 的函数时的隔离错误
- #用{}和声明定义混淆
- CTOR 声明/定义中接受的 const 限定符(LLVM 错误?)
- C++ 从一个源文件中声明/定义的变量从另一个源文件访问另一个源文件
- 无法识别的模板声明/定义
- 只在.cpp中声明/定义静态方法可以吗
- 声明/定义自定义类定制对象的正确方法
- typedef声明定义未命名类时链接失败
- 用visual c++实现COM对象的声明/定义和实例化
- VS 2012中的显式模板声明/定义
- 命名空间内的友元函数声明/定义