是`extern" C"`是函数类型的一部分?

时间:2014-10-30 07:25:45

标签: c++ c c++11 calling-convention

我没有看到标准中的任何评论,除了链接相关的事情。

虽然标准对调用约定没有任何说明,但现实世界中C和C ++之间的调用约定可能不同,所以我期望C函数和C ++函数的类型不同。但似乎没有,特别是在GCC。

#include <type_traits>

extern "C" {
  int c_func(int);
}

int cpp_func(int);

static_assert(!std::is_same<decltype(c_func), decltype(cpp_func)>::value,
              "It should not be the same type");

static_assert失败,因为GCC认为这些函数具有相同的类型。

  • extern "C"是函数类型的一部分吗?
  • 如何检查函数是否使用C调用约定或C ++调用约定?

1 个答案:

答案 0 :(得分:16)

该标准明确指出语言链接确实是函数 type 本身的属性:

  

所有函数类型,具有外部链接的函数名称和具有外部链接的变量名称都具有   语言链接。

如果不够清楚,有一个注释(强调我的),使预期的含义明确:

  

[注意:因为语言链接是函数类型的一部分,,当通过指向C的指针进行间接时   函数,结果左值引用的函数被认为是C函数。 - 结束说明]

此外,

  

两种不同语言的功能类型    链接是不同的类型,即使它们是相同的。

所以第一个问题的答案是:

  • extern "C"是函数类型的一部分。

但是,大多数编译器都无法区分具有C和C ++语言链接的函数类型。例如,这是GCC中的长期错误(https://gcc.gnu.org/bugzilla/show_bug.cgi?id=2316;请参阅重复列表)。我没有仔细阅读整个帖子,但是如果GCC开始强制执行它们确实是不同类型的规则,那么很多现有代码似乎都会破坏。这可能也是为什么其他编译器也不符合标准的原因。

鉴于此,您的第二个问题的答案似乎是:

  • 在编译时可能没有可移植的方法来执行此检查。当然,在翻译之后,你总是可以进入并查看目标文件,看看名称是否被破坏。

理论上,你的静态断言应该按照你认为应该的方式工作。实际情况并非如此。

<强>附录:

如果我对标准的理解是正确的,那么例如以下函数模板

template <typename R, typename... A>
void f(R(*)(A...));

无法实例化以生成一个函数,该函数接受指向C语言链接作为参数的函数的指针,因为类型R(*)(A...)是“指向函数与C ++语言链接的指针采用类型A...的参数并返回R“。

如果编译器真的像这样工作,很容易看出你如何能够一般性地确定函数是否具有C或C ++语言链接。

但是这个例子也应该清楚地表明,如果编译器真的以这种方式工作,现有代码会破坏多少。