使用外"C"时,带牙套或不带牙套有区别吗?
Is there a difference between with braces or without when using extern "C"?
所以,在接受James Kanze和Loki Astari关于C链接的教育时,我想知道这一点:
extern "C" int foo1 (void (*)());
extern "C" { int foo2 (void (*)()); }
经过我的教育,我认为一定是foo1
只拿一个带C++联动的功能指针,而foo2
只拿一个带C联动的函数指针。我的理解正确吗?C++标准中是否有特定的参考资料来解释我上面示例中的差异?
编辑:为了让每个人都更容易遵循,这里有一个粘贴,其中包含C++ 11草案标准中的相关部分。
foo1 获取指向 C 函数的指针,如 [dcl.link] 7.5p4 所示
在链接规范中,指定的语言链接适用于 所有函数声明符的函数类型,函数名称 外部链接,以及声明了外部链接的变量名称 在联动规范内。[示例:
extern "C" void f1(void(*pf)(int));
名称 f1 及其函数类型有 C 语言
linkage; pf 是指向 C 函数的指针
该示例直接适用于foo1
,并且添加的强调突出了我认为的原因。函数的参数列表包含参数的函数声明符,并且所有函数声明符都受链接规范的影响。这适用于支撑和非支撑连杆规格。
不使用大括号时的一些区别是,名称会自动extern
,并且禁止显式使用存储说明符。
extern "C" int i; // not a definition
int main() {
i = 1; // error, no definition
}
extern "C" static void g(); // error
作为此差异很重要的示例,请考虑包含以下内容的标头:
extern "C" int a;
extern "C" double b;
extern "C" char c;
有人可能会想将其更改为:
extern "C" {
int a;
double b;
char c;
}
但这是不正确的,因为这会将声明转换为定义。相反,使用 extern "C" {}
的正确代码是:
extern "C" {
extern int a;
extern double b;
extern char c;
}
当您有许多声明和定义时,将使用大括号。通常,您可以在头文件中看到C
代码的开始和结束
C++
#ifdef __cplusplus
extern "C" {
#endif
// C stuff here to be available for C++ code
#ifdef __cplusplus
}
#endif
我可以推荐阅读有关"名称重整"的信息,http://en.wikipedia.org/wiki/Name_mangling extern "C"
是回退到C
链接名称约定的关键。
extern "C" int foo1 (void (*)());
extern "C" { int foo2 (void (*)()); }
这些都是一样的。 使用大括号的主要原因是如果您有多个功能,例如:
extern "C" int foo1 (void (*)());
extern "C" int foo2 (void (*)());
extern "C" int foo3 (void (*)());
extern "C" int foo4 (void (*)());
可以更简单地写成:
extern "C" {
int foo1 (void (*)());
int foo2 (void (*)());
int foo3 (void (*)());
int foo4 (void (*)());
}
此外,如果您尝试创建一个同时适用于 C 和 C++ 的头文件,则可能需要将其编写为:
#ifdef __cplusplus
extern "C" {
#endif
int foo1 (void (*)());
int foo2 (void (*)());
int foo3 (void (*)());
int foo4 (void (*)());
#ifdef __cplusplus
}
#endif
附言我不知道任何编译器在函数指针的"C++链接"或"C 链接"之间存在差异。 当我们谈论 C 或C++链接时,我们谈论的是编译器如何破坏名称。 对于函数指针,您传递的是指针,因此名称无关紧要。 调用约定相同很重要,但对于 C 和 C++ 通常是相同的,因为人们可以自由地混合这些语言。
- 在 typedef 内部使用 const 关键字和在 typedef 外部使用 const 关键字之间有区别吗?
- 为什么这里的大括号和括号初始化有区别?
- 使用短运算符的字符串连接有区别吗?
- static_cast<unsigned>(签名)与标准::bit_cast<unsigned>(签名)之间有区别吗?
- 在调用函数时,ptr** 和 ptr*& 之间是否有区别,或者首选C++?
- 在类内和类外的定义处执行类转发声明是否有区别
- CRTP:为什么获得嵌套类型和派生类的嵌套方法有区别
- 使用 std::move 将参数传递给函数,如果该参数声明为按值传递或使用移动操作数 &&,是否有区别?
- c++ 类中的静态常量变量和常量变量在存储方面是否有区别
- 为什么 .cpp 文件和 .h 文件之间有区别?
- C++:调用运算符和调用其实现之间有区别吗
- 将全局声明为类声明语句的一部分与使用单独的语句声明全局之间是否有区别
- 用户定义的类和标准类之间有区别吗?
- 这两个数组之间有区别吗?
- 这些在C 中初始化C数组的方式之间有区别吗?
- vector.size()= 0和vector.empty()之间是否有区别
- 显式运算符 = 调用和 = 运算符之间是否有区别
- 这两种初始化成员变量的方法之间有区别吗?
- 忽略内存消耗,使用“int”或“char”是否有区别
- 在DirectX中,深度值中存储了哪些值?这在DX9和DX11之间有区别吗