extern"C"静态void*函数

nin*_*ies 8 c++

在阅读了extern和static之后,我很困惑地遇到了下面这行代码:

extern "C" static void* foo(int* a){
    return foo1(a);
}
Run Code Online (Sandbox Code Playgroud)

为什么这不会产生任何错误?

小智 6

以下也编译并执行与您的行相同的操作:

extern "C" {
  static void* foo(int* a){
    return foo1(a);
  }
}
Run Code Online (Sandbox Code Playgroud)

static那意味着foo()将只在文件范围内使用,并覆盖extern "C",当谈到联动。通常,extern "C"如果/当导出时,会影响链接器使用的函数的名称,以便在链接整个程序时可以从其他目标文件调用该函数。通常,当您想要链接到从 C 源代码构建的目标文件时foo(),或者您想要定义的位置foo()以便 C 代码可以调用它时,就会使用它。然而,根本没有被导出的static原因foo,所以它基本上甚至没有名字(它有内部链接,而不是外部链接)。

extern "C"也有次要作用。这也成为部分类型foo。也就是说,C++ 代码将被foo视为具有类型extern "C" void(int*)。基本上,这控制调用约定。例如,C++ 编译器可以在寄存器/堆栈中以与 C 编译器不同的方式排列参数。使foo是C功能的装置,这将使用C约定,而不是C ++约定。这使得例如将函数指针传递给需要指向fooC 函数的指针的 C 函数是安全的。例如,标准库有

extern "C" typedef int C_CMP(void const*, void const*);
extern "C++" typedef int CXX_CMP(void const*, void const*);
void std::qsort(void *, std::size_t, std::size_t, C_CMP);
void std::qsort(void *, std::size_t, std::size_t, CXX_CMP);
Run Code Online (Sandbox Code Playgroud)

使用extern "C",&foo传递给第一个重载,但没有它/使用extern "C++",则传递给第二个。它不会是安全的声明foo没有extern "C",然后尝试将它传递到C函数需要一个指向C函数。它可能起作用,但它也可能会严重崩溃。添加extern "C"并且它变得正确 - 你是安全的。

  • 我很确定 extern/static 函数的原因是传递一个指向需要 C 回调的东西的指针。严格来说,将指向具有 C++ 链接的函数的指针传递给需要 C 可调用函数的东西是无效的,即使它在实践中有效。通常使用一个普通的老式`extern "C"` 函数,但为什么要将全局命名空间弄乱只需要一个指针指向的东西呢? (7认同)
  • 事实上,C++11 标准使用`extern "C" { static void f4(); }` 以7.5“联动规范”为例。随附的注释说,“函数 f4 的名称具有内部链接(不是 C 语言链接)并且函数的类型具有 C 语言链接”。 (4认同)
  • C++ 标准在注释中作出评论:“特定的语言链接可能与表示具有外部链接、**或特定调用约定**等的对象和函数名称的特定形式相关联”。但是,该标准明确禁止在与 `extern "C"` 相同的语句中使用存储说明符(如 `static`)。但是嵌套形式是允许的。毫无疑问,这是该语言的一个奇怪的角落。 (2认同)