Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/arduino/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么不匹配的原型和定义以及空参数列表在GCC和Clang中给出了不同的结果?_C_Language Lawyer_C11_Stackoverflow - Fatal编程技术网

为什么不匹配的原型和定义以及空参数列表在GCC和Clang中给出了不同的结果?

为什么不匹配的原型和定义以及空参数列表在GCC和Clang中给出了不同的结果?,c,language-lawyer,c11,stackoverflow,C,Language Lawyer,C11,Stackoverflow,给定(简化)代码段: void foo(int a, int b); // declaration with prototype int main(void) { foo(1, 5); // type-checked call (i.e. because of previous prototype) return 0; } void foo() // old-style definition (with empty argument list) { } 和命令行选项(不过

给定(简化)代码段:

void foo(int a, int b); // declaration with prototype

int main(void)
{
    foo(1, 5); // type-checked call (i.e. because of previous prototype)
    return 0;
}

void foo() // old-style definition (with empty argument list)
{

}
和命令行选项(不过,正如我所检查的,它们并不重要):

gcc 7.2未能编译,错误消息如下:

错误:参数数与原型不匹配

而Clang4.0则毫无怨言地翻译了它

根据C标准,哪个实现是正确的?旧式定义“取消”以前的原型是否有效?

我没有引用标准(编辑:参考
C11
,第6.7.6.3章/P14),但根据我的理解,
gcc
是正确的,因为你自相矛盾

您承诺在函数定义中,在声明列表中,您将有两个类型为
int
的参数,但它们不存在。在函数定义的情况下,空列表表示该函数不应接受任何参数。因此存在违反约束的情况,
gcc
有权投诉

这似乎是一个问题,因为它至少不会产生警告


引述:

第§6.7章,第4页(约束条件)

同一范围内引用同一对象或函数的所有声明应指定兼容类型

然后,第§6.7.6.3章,第14页

标识符列表仅声明函数参数的标识符。空的 作为函数定义一部分的函数声明器中的列表指定 函数没有参数。函数声明符中的空列表,它不是 该函数的定义指定没有关于函数的数量或类型的信息 提供了参数

因此,这构成了违反约束,并保证发出诊断。

免责声明:我不是一个,但我玩一个

如果编译器没有发出诊断,那么它将是不符合要求的,如果编译器声称符合要求,则可能被视为错误。

C.2011§6.7.6.3¨14(重点):

标识符列表仅声明函数参数的标识符一个空的 作为函数定义一部分的函数声明器中的列表指定 函数没有参数。函数声明符中不属于 该函数的定义指定没有关于函数的数量或类型的信息 提供了参数

因此,
foo
的定义没有指定任何参数,而先前的
foo
声明指定了两个参数

C.2011第6.7.6.3条第15款:

对于要兼容的两种功能类型,两者都应指定兼容的返回类型。146) 此外,参数类型列表,如果两者都存在,则其数量应一致 参数和省略号终止符的使用;应具有相应的参数 兼容类型。
146)如果两种函数类型均为“旧式”,则不比较参数类型

因此,
foo
的两个声明符不兼容。
该死!发件人:


众所周知,
void foo()
即使在定义中也不提供原型。该定义中的
foo
类型是
void foo()
,而不是
void foo(void)
,以及
void foo()
void foo(int,int)
是兼容的类型。这个答案是不正确的

上述标准文本中强调的部分是一个漏洞,允许在参数数量上存在分歧,但类型兼容。尽管函数定义指定了一个不带参数的函数,但由于参数类型列表实际上缺失,因此其函数原型中的
foo
类型与函数定义中的
foo
类型之间实际上没有不兼容

因此,Clang4.0似乎是正确的,因为没有违反约束

我的原始论点变得无效,所以编辑掉我原始答案的那一部分


在评论中,您实际展示了以下示例:

void foo () {}

int main () { foo(1, 2); return 0; }
并询问编译器为什么不对此案例进行投诉。这实际上已经解决了,但简而言之:C.2011仍然接受K&R C函数定义语法。因此,虽然
void foo(){}
是一个不接受参数的定义,但用于参数验证的原型与
void foo()相同,因为空参数列表被解析为K&R。强制正确参数检查的现代C语法将使用
void foo(void){}

(C11,6.7p4约束)“同一范围内引用同一对象或函数的所有声明应指定兼容类型”

(C11,6.7.6.3p14)“标识符列表仅声明函数参数的标识符。作为该函数定义一部分的函数声明器中的空列表指定函数没有参数。[…]”

我的意见是违反了6.7p4的约束,必须发布诊断

编辑:

正如他所指出的,这实际上是不正确的。6.7.6.3p14并不意味着
void foo(){}
根据提供了
foo
的原型。从这个意义上说,6.7p4约束没有被违反,因此clang不抱怨是正确的

来自C标准(6.7.6.3函数声明器(包括原型))

15对于要兼容的两种功能类型,两者均应规定 兼容的返回类型。146)此外。。。如果一个类型有一个参数 类型列表,其他类型由函数定义指定 包含(可能为空)标识符列表的,双方应在以下方面达成一致: 参数的数量以及每个原型参数的类型 应兼容
void foo () {}

int main () { foo(1, 2); return 0; }