使用extern“C”时是否有大括号或没有大括号?

时间:2012-08-08 22:10:01

标签: c++

所以,在schooled by James Kanze and Loki Astari about C linkage期间,我对此感到疑惑:

extern "C" int foo1 (void (*)());
extern "C" { int foo2 (void (*)()); }

在我上学之后,我认为必须是foo1只接受带有C ++链接的函数指针,而foo2只接受带有C链接的函数指针。我的理解是否正确? C ++标准中是否有特定的参考资料来解释我上面例子中的差异?

修改:让每个人都可以更轻松地跟进here's a pastebin with the relevant part from the C++ 11 draft standard

3 个答案:

答案 0 :(得分:9)

foo1获取指向C函数的指针,如[dcl.link] 7.5p4

所示
  

linkage-specification 中,指定的语言链接适用于   所有函数声明符的函数类型,函数名称   外部链接和声明了外部链接的变量名称   在链接规范内。 [实施例:

     

extern "C" void f1(void(*pf)(int));
   //名称f1及其功能类型具有C语言
   //连接; 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;
}

答案 1 :(得分:1)

当您有许多声明和定义时,将使用大括号。通常,您可以在标头文件中看到开头和结尾,以便在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链接名称约定的关键。

答案 2 :(得分:1)

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

P.S。我不知道任何编译器的功能指针的“C ++链接”或“C链接”之间存在差异。当我们谈论C或C ++链接时,我们正在讨论编译器如何破坏名称。对于函数指针,您传递指针,因此名称无关紧要。重要的是调用约定是相同的,但它通常与C和C ++相同,因为人们可以自由地混合这些语言。