11

使用正常功能,可以编写

extern "C" int Frotz(int);  // in a header

int Frotz(int x) { return x; }

然而,对于函数指针,这似乎在编译器之间的实现不一致。

extern "C" int Klutz(int (*)(int), int);

int Klutz(int (*fptr)(int), int x) { return (*fptr)(x); }

在声明中,参数也是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"符号?

编辑 1

我可以使用 typedef 来消除具有 C 或 C++ ABI 的函数指针的歧义,但我感兴趣的是这里的代码 (a) 是否定义Klutz为具有 C++ 链接,(b) 将其定义为具有 C 链接,或者 (c)根据标准是模棱两可的,因此编译器可以自由选择如何解释它。

编辑 2

这似乎是一个已知问题,至少对于那些带有可搜索错误跟踪器的编译器而言。在我的测试中,GCC、Clang、Intel、MSVC、IBM XL、PathScale、PGI 和 Open64 都无法区分除了语言链接之外相同的函数类型,这是标准明确要求的(参见第 7.5.1 节,引用于接受的答案)。解决这个问题会破坏很多现有代码并需要更改 ABI。我不知道有任何编译器实际上对 C 与 C++ 语言链接使用不同的调用约定。

  • GCC 错误:“寻找理由要求从下一个标准中删除此功能是相关的 ;-)” ...“我们甚至可能决定使用官方 WONTFIX。”

  • Clang 错误:“我害怕实际执行此规则,因为正确执行意味着使语言链接成为规范类型的一部分,这将破坏大量代码。”

4

1 回答 1

8

不保证 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); }

这里有一些关于这个问题的讨论。


我只有一份草稿。从 7.5p1 开始:

具有不同语言链接的两个函数类型是不同的类型,即使它们在其他方面相同。

我对此的解读是,您的 firstKlutz的第一个参数与您的 second 的第一个参数具有不同的类型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); }

不根据语言链接区分函数类型的编译器将在此代码上生成重新定义错误。例如,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
于 2013-03-20T23:38:16.530 回答