使用外"C"时,带牙套或不带牙套有区别吗?

Is there a difference between with braces or without when using extern "C"?

本文关键字:有区别      更新时间:2023-10-16

所以,在接受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++ 通常是相同的,因为人们可以自由地混合这些语言。