外部“C”,重载和函数指针的可能模糊性 [英] Possible ambiguity with extern "C", overloading, and function pointers

查看:123
本文介绍了外部“C”,重载和函数指针的可能模糊性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用正常函数,可以写

  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 ++语言链接使用不同调用约定的编译器。




  • GCC错误:找出原因要求从下一个标准中删除此功能


  • 俚语错误:我害怕实际执行这条规则,因为这样做正确意味着语言联系是规范的一部分类型,这将打破一吨代码。



解决方案

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆