C++ “外部”;";静态void*函数

C++ “外部”;";静态void*函数,c++,C++,在阅读了有关extern和static的内容后,我很困惑地发现下面这行代码: extern "C" static void* foo(int* a){ return foo1(a); } 为什么这不会产生任何错误?以下代码也会编译并执行与您的代码行相同的操作: extern "C" { static void* foo(int* a){ return foo1(a); } } static意味着foo()将仅在文件范围内可用,并且当涉及到链接时,它将覆盖extern“

在阅读了有关extern和static的内容后,我很困惑地发现下面这行代码:

extern "C" static void* foo(int* a){
    return foo1(a);
}

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

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

extern "C" {
  static void* foo(int* a){
    return foo1(a);
  }
}
static
意味着
foo()
将仅在文件范围内可用,并且当涉及到链接时,它将覆盖
extern“C”
。通常,
extern“C”
会影响链接器在导出时使用的函数名,以便在链接整个程序时可以从其他对象文件调用该函数。通常,当您想要链接到从定义了
foo()
的C源代码生成的对象文件,或者想要定义
foo()
以便C代码可以调用它时,使用此选项。然而,
static
导致
foo
根本无法导出,因此它基本上连名字都没有(它有内部链接,没有外部链接)

extern“C”
还有一个次要效果。它也成为
foo
类型的一部分。也就是说,C++代码将看到代码> Foo作为类型<代码>外部“C”空隙(INT*)< /代码>。基本上,它控制调用约定。C++编译器可以在寄存器/堆栈上以不同于C编译器的方式排列参数。将<代码> Foo< /Cord>作为C函数意味着它将使用C约定而不是C++约定。这样可以安全地将指向
foo
的函数指针传递给需要指向C函数指针的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);

使用
extern“C”
,将
&foo
传递给第一个重载,但如果没有它,则将
extern“C++”
传递给第二个重载。在没有
extern“C”
的情况下声明
foo
,然后尝试将其传递到需要指向C函数的指针的C函数中是不安全的。它可能会工作,但也可能会坏得很厉害。添加
extern“C”
,它就正确了,您是安全的。

好奇:哪个编译器在哪个平台上?请注意,函数体无法编译(
返回foo1(int*a);
在C++中无效)。在Mac OS X 10.11.6上使用G++6.1.0进行编译时,从源文件
bust cpp.cpp
,使用命令行:
G++-O3-G-I./inc-std=c++11-Wall-Wextra-Werror-c bust cpp.cpp
I获取消息:
bust cpp.cpp:1:12:错误:链接规范中指向
extern“c”的“static”无效使用静态void*foo(int*a){
。这可能是在一个从未编译过的文件中。如果您这样做,CC-5.1将无法很好地编译(更可能是“被迫”)使用古语编译器:……这很奇怪。你应该报告那些升级后不会编译的权限。不清楚为什么你想要C样式链接来连接那些定义它的C++源文件不能访问的函数。代码看起来非常模糊,几乎完全没有意义。我想T。如果函数的指针返回到某个地方,C链接是至关重要的,它可能在一个C和C++链接有区别的机器上起作用。外部可链接。正如我在对Dan Haydar回答的评论中提到的,它也可能影响调用约定。事实上,该标准显示并解释了
外部“C”中声明的
静态
函数的示例在外部链接的部分中,“块”。我很确定外部/静态函数的原因是传递一个指向C回调的指针。严格来说,将指针传递到C++链接的函数到需要C调用函数的函数是无效的,即使它在实践中也是有效的。通常是普通的。使用了旧的
extern“C”
函数,但是为什么要将全局名称空间凌乱到只需要一个指针的地方呢?事实上,C++11标准使用
extern“C”{static void f4();}
作为7.5“链接规范”中的一个示例。附带的注释说,“函数f4的名称具有内部链接(不是C语言链接)并且函数的类型具有C语言链接。仅执行“静态”就足以将foo()排除在全局命名空间之外。关于不能传递“C”的部分链接函数是指向C++代码的指针,反之亦然。链接是关于命名的,而指针的功能是物理地址。它们似乎是正交的概念。然后,我作为语言律师的日子已经过去了,所以…C++标准在注释中做出评论:“特定语言链接可能与表示具有外部链接的对象和函数的名称的特定形式相关联,或与特定调用约定等相关联”。但是,该标准明确禁止在与
外部链接“C”相同的语句中使用存储说明符(如
static
)“
。但是嵌套形式是允许的。毫无疑问,它是语言中的一个奇怪的角落。
返回foo1(int*a);
这可以编译吗?真的吗?