在这种情况下,GCC 和 clang 是否显示与 Visual Studio 相同的结果,关于语言链接?

Do GCC and clang show the same result as Visual Studio on this case, about language linkage?

本文关键字:于语言 结果 语言 链接 clang GCC 这种情况下 是否 显示 Studio Visual      更新时间:2023-10-16

[dcl.link]/4:

联动规格嵌套。当联动规格嵌套时, 最内在的是语言联系。联动规格 不建立范围。仅应出现联动规范 在命名空间范围内。在联动规范中,指定的 语言链接适用于所有函数的功能类型 声明符、带外部链接的函数名称和变量 在链接规范中声明的具有外部链接的名称。 [ 示例:

extern "C"                      // the name f1 and its function type have C language linkage;
void f1(void(*pf)(int));      // pf is a pointer to a C function

— 结束示例 ]

请注意,传递给下面c_f()函数&foo指针不是指向 C 函数的指针。此代码在VS2017中正常编译和链接。但根据[dcl.link]/4的说法,它不应该。

文件main.cpp

#include <stdio.h>
extern "C"                          // the name c_f and its function type have C language linkage;
void c_f(void(*pf)(int));           // pf is a pointer to a C function
void foo(int i) {
printf("%dn", i);
}
extern "C" void c_foo(int);
int main() {
c_foo(1);       // Calls c_foo(int) defined in other.c
c_f(&foo);      // Calls c_f(void(*)(int)) defined in other.c, but &foo is not a pointer to a C function !! 
}

文件other.c

#include <stdio.h>
void c_f(void(*pf)(int)){
pf(2);
}
void c_foo(int i) {
printf("%dn", i);
}

我很想知道 clang 和 GCC 是否符合标准,但我无法在 Web 编译器中验证这一点。

编辑

我突然意识到,在上述问题上,我真的不需要两个文件来验证 clang 和 GCC 是否符合标准。如果标准要求 C 函数的地址,作为函数c_f()的参数,并且main.cpp中的代码提供C++函数的地址,则C++编译器在编译此文件时必须抱怨1。但这在叮当和海湾合作委员会中都不会发生。那么,我不妨说,叮当和海湾合作委员会在这方面也是有缺陷的。

1(如果我们假设需要诊断

你的代码根据 [dcl.link]/1 和 [expr.call]/1 显示未定义的行为(重点是我的(:

[dcl.link]/1:

所有函数类型、具有外部链接的

函数名称和具有外部链接的变量名称都具有语言链接。[ 注意:与具有语言链接的实体关联的某些属性特定于每个实现,此处不进行介绍。例如,特定的语言链接可能与表示具有外部链接的对象和函数名称的特定形式相关联,或者与特定的调用约定相关联,等等。 — 尾注 ] 所有函数类型、函数名称和变量名称的默认语言链接是C++语言链接。具有不同语言链接的两个函数类型是不同的类型,即使它们在其他方面相同

[expr.call]/1:

函数

调用是一个后缀表达式,后跟括号,其中包含可能为空的、以逗号分隔的初始值设定项子句列表,这些初始值设定项子句构成函数的参数。后缀表达式应具有函数类型或函数指针类型。对于对非成员函数或静态成员函数的调用,后缀表达式应为引用函数的左值(在这种情况下,后缀表达式上禁止函数到指针的标准转换(,或者应具有函数指针类型。通过函数类型与被调用函数定义的函数类型的表达式调用函数会导致未定义的行为([dcl.link](。对于对非静态成员函数的调用,后缀表达式应是隐式([class.mfct.non-static]、[class.static](或显式类成员访问,其 id-expression 是函数成员名称,或指向选择函数成员的成员的指针表达式;调用作为对象表达式引用的类对象的成员。在隐式类成员访问的情况下,隐含的对象是 this 指向的对象。[注意:形式为f((的成员函数调用被解释为(*this(.f(((参见[class.mfct.non-static](。如果使用函数或成员函数名称,则可以重载该名称,在这种情况下,应根据 [over.match] 中的规则选择适当的函数。如果所选函数是非虚拟函数,或者类成员访问表达式中的 id 表达式是限定 id,则调用该函数。否则,将调用对象表达式动态类型中的最终覆盖器;此类调用称为虚函数调用。[ 注意:动态类型是对象表达式的当前值所引用的对象类型。[class.cdtor] 描述了当对象表达式引用正在构造或销毁的对象时虚拟函数调用的行为。— 尾注 ]