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

Is `extern "C"` a part of the type of a function?

本文关键字:一部分 函数 外部 类型      更新时间:2023-10-16

除了链接相关的内容外,我在标准中没有看到任何注释。

虽然标准没有说明调用约定,但在现实世界中,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");

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

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

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

所有函数类型、具有外部链接的函数名和具有外部链接功能的变量名都有一个语言链接

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

[注意:因为语言链接是函数类型的一部分,所以在通过指向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++语言链接。

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