外部“C”,重载和函数指针的可能模糊性 [英] Possible ambiguity with extern "C", overloading, and function pointers
问题描述
使用正常函数,可以写
externCint Frotz // in a header
int Frotz(int x){return x; }
然而,使用函数指针,这似乎是在编译器之间实现不一致。
externCint Klutz(int(*)(int),int);
int Klutz(int(* fptr)(int),int x){return(* fptr)(x); }
在声明中,参数也为 externC code>。在定义中,大多数编译器看起来与这些函数匹配,并使
Klutz
一个 externC
函数。然而,Sun和Cray编译器将这些函数解释为不同的,产生一个重载的 int Klutz(int(* fptr)(int),int x)
一个链接时间错误。
虽然C ++ 98和C ++ 11的第7.5.5节保证了 Frotz
,我不能确定标准是否不清楚是否 externC
匹配应在检查重载之前或之后发生。
上面的 Klutz
生成一个错误的(C ++)符号或 externC
符号?
编辑1
我可以使用typedef来消除函数指针的歧义,使其具有C或C ++ ABI,但我感兴趣的是,这里的代码(a)是否定义
Klutz
有C ++链接,(b)定义它有C链接,或(c) 编辑2
这会显示出来是一个已知的问题,至少是那些编译器与可搜索的bug跟踪。在我的测试中,GCC,Clang,Intel,MSVC,IBM XL,PathScale,PGI和Open64都无法区分标准明确要求的除语言链接外相同的函数类型(请参见第7.5.1节接受答案)。修复这将破坏很多现有的代码,并要求ABI更改。我不知道任何实际上对C和C ++语言链接使用不同调用约定的编译器。
C ABI和C ++ ABI不能保证是相同的。因此, externC
函数指针与C ++函数指针是不同的类型。你需要这样的:
externC{
typedef int(* KlutzFuncType)
int Klutz(KlutzFuncType,int);
}
int Klutz(KlutzFuncType fptr,int x){return(* fptr)(x); }
这个问题有一些讨论这里。
我只有 draft 。从7.5p1开始:
具有不同语言链接的两种函数类型是不同类型,即使它们是相同的。
我的看法是,你的第一个 Klutz
的第一个参数的类型不同于第一个参数您的第二个 Klutz
,因此您的第二个 Klutz
应该有C ++链接。
有些C ++实现不考虑函数类型的语言链接,尽管标准说了。在下面的代码片段中, KlutzCxxFuncType
是指具有C ++链接的函数,而 KlutzCFuncType
是指具有C链接。
typedef int(* KlutzCxxFuncType)(int);
externC{
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); }
不区分基于语言链接的函数类型的编译器将在此代码上生成重定义错误。例如, g ++ 4.7.2
会发出:
prog.cpp :在函数'int Klutz(KlutzCFuncType,int)':
prog.cpp:9:5:error:redefinition'int Klutz(KlutzCFuncType,int)'
prog.cpp:8:错误:'int Klutz(KlutzCxxFuncType,int)'以前在这里定义
With normal functions, one can write
extern "C" int Frotz(int); // in a header
int Frotz(int x) { return x; }
With function pointers, however, this appears to have been implemented inconsistently between compilers.
extern "C" int Klutz(int (*)(int), int);
int Klutz(int (*fptr)(int), int x) { return (*fptr)(x); }
In the declaration, the argument is also extern "C"
. In the definition, most compilers appear to match these functions and make Klutz
an extern "C"
function. The Sun and Cray compilers, however, interpret these functions as being different, producing an overloaded int Klutz(int (*fptr)(int), int x)
, which later generates a link-time error.
Although Section 7.5.5 of C++98 and C++11 guarantees the interpretation of Frotz
, I cannot tell if the standard is ambiguous about whether extern "C"
matching should occur before or after checking for overloading.
Should Klutz
above generate a mangled (C++) symbol or an extern "C"
symbol?
EDIT 1
I could use a typedef to disambiguate the function pointer to have C or C++ ABI, but I'm interested in whether the code here (a) defines Klutz
to have C++ linkage, (b) defines it to have C linkage, or (c) is ambiguous according to the standard, so that compilers are free to choose how to interpret it.
EDIT 2
This appears to be a known issue, at least by those compilers with searchable bug trackers. In my tests, GCC, Clang, Intel, MSVC, IBM XL, PathScale, PGI, and Open64 all fail to distinguish function types that are identical except for language linkage, as explicitly required by the standard (see section 7.5.1, quoted in the accepted answer). Fixing this would break a lot of existing code and require an ABI change. I'm not aware of any compiler that actually uses a different calling convention for C versus C++ language linkage.
GCC bug: "Finding reasons to ask for the removal of this feature from the next standard is kind of relevant ;-)" ... "And we may even decide on an official WONTFIX."
Clang bug: "I'm terrified of actually enforcing this rule, because doing it properly means making language linkage part of the canonical type, which is going to break a ton of code."
The C ABI and the C++ ABI are not guaranteed to be the same. So, an extern "C"
function pointer is a different type from a C++ function pointer. You need something like this:
extern "C" {
typedef int (*KlutzFuncType)(int);
int Klutz (KlutzFuncType, int);
}
int Klutz (KlutzFuncType fptr, int x) { return (*fptr)(x); }
There is some discussion of this issue here.
I only have a copy of the draft. From 7.5p1:
Two function types with different language linkages are distinct types even if they are otherwise identical.
My reading of this is that the first parameter of your first Klutz
has a different type than the first parameter of your second Klutz
, and so your second Klutz
should have C++ linkage.
There are C++ implementations that do not take language linkage into account for function types, despite what the standard says. In the following code snippet, KlutzCxxFuncType
refers to a function with C++ linkage, while KlutzCFuncType
refers to a function with C linkage.
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); }
A compiler that does not distinguish function types based on language linkage will generate a redefinition error on this code. For example, g++ 4.7.2
will emit:
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
这篇关于外部“C”,重载和函数指针的可能模糊性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!