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

Inb*_*ong 13 c c++ calling-convention c++11

除了链接相关的东西,我没有在标准中看到任何评论.

虽然标准没有说调用约定,但在现实世界中C和C++之间的调用约定可能不同,所以我期望C函数和C++函数的类型不同.但似乎没有,特别是在海湾合作委员会.

#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");
Run Code Online (Sandbox Code Playgroud)

static_assert 由于GCC认为这些功能具有相同的类型,因此失败.

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

Bri*_*ian 16

该标准清楚地表明语言链接确实是函数类型本身的属性:

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

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

[注意:因为语言链接是函数类型的一部分,所以当通过指向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...));
Run Code Online (Sandbox Code Playgroud)

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

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

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