在 C++ 中,函数类型具有与之关联的“语言链接”(language linkage):这可以是“C++”、“C”或其他由实现定义的语言。标准明确规定:即使两个函数类型在其他方面完全相同,但若语言链接不同,则它们是不同的类型。原因是某些实现可能对 C++ 函数和 C 函数采用不同的调用约定,因此它们不能混用

然而,gcc 和 clang 并未将语言链接信息存储在类型中,因此具有不同语言链接的两个函数可以被视为相同:

#include <type_traits>
extern "C" using c_func = void ();
// this static assertion should fail, but it doesn't
static_assert(std::is_same<c_func, void ()>::value);

这也可能在重载接受函数指针参数的函数时导致错误的编译失败:

extern "C" using c_func = void ();
void f(c_func *) {}
void f(void (*)()) {}

上述代码本应能够编译,但 gcc 和 clang 都认为参数列表相同,因此这违反了单一定义规则(one definition rule)

在我看来,责任并不在于 gcc 或 clang,而在于标准。也就是说,标准是错误的,应当更新以使此行为由实现定义。gcc 和 clang 无法更改其行为,因为那将导致 ABI 破坏(在 mangled 名称中,extern "C" 函数类型将被以不同方式编码)。而且它们也没有理由进行此更改:据我所知,在几乎所有平台上,C 和 C++ 的调用约定都是相同的