14

因此,在James Kanze 和 Loki Astari 对 C 链接进行教育时,我想知道这一点:

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

毕业后,我认为它必须是foo1只接受一个带有C++链接的函数指针,而foo2只接受一个带有C链接的函数指针。我的理解正确吗?C++ 标准中是否有具体的参考资料可以解释我上面示例中的差异?

编辑:为了让每个人都更容易理解,这里有一个包含 C++ 11 草案标准相关部分的 pastebin

4

3 回答 3

9

foo1 采用指向 C 函数的指针,如 [dcl.link] 7.5p4 中所示

链接规范中,指定的语言链接适用于所有函数声明符的函数类型、具有外部链接的函数名以及链接规范中声明的具有外部链接的变量名。[例子:

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;
}
于 2012-08-08T22:48:41.400 回答
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_manglingextern "C"是回退到C链接名称约定的关键。

于 2012-08-08T23:11:01.303 回答
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

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

于 2012-08-08T23:11:56.723 回答