使用普通功能,可以编写
extern "C" int Frotz(int); // in a header
int Frotz(int x) { return x; }
Run Code Online (Sandbox Code Playgroud)
但是,对于函数指针,这似乎在编译器之间不一致地实现.
extern "C" int Klutz(int (*)(int), int);
int Klutz(int (*fptr)(int), int x) { return (*fptr)(x); }
Run Code Online (Sandbox Code Playgroud)
在声明中,论点也是extern "C"
.在定义中,大多数编译器似乎满足这些功能,使Klutz
的extern "C"
功能.但是,Sun和Cray编译器会将这些函数解释为不同,从而产生过载int Klutz(int (*fptr)(int), int x)
,从而产生链接时错误.
虽然C++ 98和C++ 11的7.5.5节保证了解释Frotz
,但我无法判断标准是否extern "C"
在检查重载之前或之后是否应该进行匹配时是不明确的.
Klutz
上面应该生成一个受损的(C++)符号或extern "C"
符号吗?
我可以使用typedef消除函数指针的歧义,使其具有C或C++ ABI,但我感兴趣的是这里的代码(a)是否定义Klutz
了C++链接,(b)将其定义为具有C链接,或者(c)根据标准是模糊的,因此编译器可以自由选择如何解释它.
这似乎是一个已知问题,至少是那些具有可搜索错误跟踪器的编译器.在我的测试中,GCC,Clang,Intel,MSVC,IBM XL,PathScale,PGI和Open64都无法区分除语言链接之外相同的功能类型,如标准明确要求的那样(参见7.5.1引用的部分)接受的答案).修复此问题会破坏大量现有代码并需要进行ABI更改.我不知道任何编译器实际上使用不同的C语言与C++语言链接的调用约定.
海湾合作委员会的错误:"找到要求从下一个标准中删除此功能的理由是相关的;-)"......"我们甚至可以决定官方的WONTFIX."
Clang bug:"我害怕实际执行这条规则,因为正确地执行它意味着将语言链接作为规范类型的一部分,这将打破大量代码."
C ABI和C++ ABI不保证是相同的.因此,extern "C"
函数指针是与C++函数指针不同的类型.你需要这样的东西:
extern "C" {
typedef int (*KlutzFuncType)(int);
int Klutz (KlutzFuncType, int);
}
int Klutz (KlutzFuncType fptr, int x) { return (*fptr)(x); }
Run Code Online (Sandbox Code Playgroud)
有这个问题的一些讨论在这里.
我只有一份草稿副本.从7.5p1:
具有不同语言链接的两种函数类型是不同的类型,即使它们在其他方面是相同的.
我对此的解读是,第一个参数的第Klutz
一个参数与第二个参数的类型不同Klutz
,因此第二个参数Klutz
应该具有C++链接.
尽管标准规定,但有些C++实现并没有将函数类型的语言链接考虑在内.在下面的代码片段中,KlutzCxxFuncType
引用具有C++链接KlutzCFuncType
的函数,而引用具有C链接的函数.
typedef int (*KlutzCxxFuncType)(int);
extern "C" {
typedef int (*KlutzCFuncType)(int);
int Klutz (KlutzCFuncType, int);
}
int Klutz (KlutzCxxFuncType fptr, int x) { return (*fptr)(x); }
int Klutz (KlutzCFuncType fptr, int x) { return (*fptr)(x); }
Run Code Online (Sandbox Code Playgroud)
不基于语言链接区分函数类型的编译器将在此代码上生成重定义错误.例如,g++ 4.7.2
将发出:
prog.cpp: In function ‘int Klutz(KlutzCFuncType, int)’:
prog.cpp:9:5: error: redefinition of ‘int Klutz(KlutzCFuncType, int)’
prog.cpp:8:5: error: ‘int Klutz(KlutzCxxFuncType, int)’ previously defined here
Run Code Online (Sandbox Code Playgroud)