22

我刚刚注意到 C++ 标准说 C 和 C++ 函数具有不同且不兼容的类型,即使它们的类型签名相同(有关更多信息,请参阅此问题)。这意味着从技术上讲,您不允许将 C++ 函数传递给 C 函数,例如pthread_create().

我很好奇是否有任何平台在使用,其中两个 ABI 实际上是不同的(除了明显的名称修饰差异)。具体来说,有谁知道这个 C++ 程序无法编译和运行的任何平台?

#include <assert.h>

extern "C" int run(int (*f)(int), int x) { return f(x); }

int times2(int x) { return x * 2; }

int main(int argc, char *argv[]) {
  int a = times2(argc);
  // This is undefined behavior according to C++ because I am passing an
  // "extern C++" function pointer to an "extern C" function.
  int b = run(&times2, argc);
  assert(a == b);
  return a;
}
4

1 回答 1

8

我不知道任何平台的 ABI 不同,但即使 C 和 C++ 调用约定相同,C++ 标准也要求编译器为程序发出诊断。带有 C 语言链接的指向函数的指针与带有 C++ 语言链接的指向函数的指针是不同的类型,因此您应该能够run()像这样重载:

extern "C" int run(int (*f)(int), int x) { return f(x); }
extern "C++" int run(int (*f)(int), int x) { return f(x); }

现在,当您调用run(times)它时,它应该调用第二个,因此第一个是不可调用的(没有从带有 C 语言链接的指向函数的指针到带有-的指向函数的指针的转换C++ 语言链接),因此原始代码应导致编译器诊断。但是,大多数编译器都会出错,例如http://gcc.gnu.org/bugzilla/show_bug.cgi?id=2316

注意 Solaris 编译器诊断不兼容的语言链接,作为警告:

"t.c", line 11: Warning (Anachronism): Formal argument f of type extern "C" int(*)(int) in call to run(extern "C" int(*)(int), int) is being passed int(*)(int).

如果您run使用一个extern "C++"函数重载,它会正确调用该函数extern "C++"for run(times)

于 2013-05-17T18:18:36.813 回答