繁体   English   中英

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

[英]Why does mismatched prototype and definition with empty argument list give different results in GCC and Clang?

给定(简化)代码片段:

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)
{

}

和命令行选项(但是,因为我检查它们并不重要):

-x c -std=c11 -pedantic -Wall

gcc 7.2无法编译它,并显示以下错误消息:

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

虽然clang 4.0翻译它没有任何投诉。

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

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

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

我认为违反6.7p4的约束并且必须发布诊断。

编辑:

正如@hvd指出的那样,实际上并不正确。 6.7.6.3p14并不意味着void foo() {}根据DR#317foo提供原型。 从这个意义上说,6.7p4约束没有被违反,所以clang是不对的抱怨。

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

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

C.2011§6.7.6.3¶14(强调我的):

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

因此, foo的定义没有指定参数,而foo的声明早先指定了两个参数。

C.2011§6.7.6.3¶15:

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

因此, foo的两个声明foo不兼容。
党! 来自@ hvd的评论

已经确定void foo()不提供原型,即使在定义中也是如此。 有一个DR明确地回答了这个问题。 该定义中的foo类型为void foo() ,而不是void foo(void)void foo()void foo(int, int)是兼容类型。 这个答案是不正确的。

标准中上面强调的部分是漏洞,它允许参数数量不一致,但兼容类型。 虽然功能定义指定一个函数,它不带任何参数,因为参数类型列表实际上是缺少,但是实际上的类型之间没有不兼容foo在其函数原型和类型foo的函数定义。

因此,clang 4.0似乎是正确的,因为没有约束违规。

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


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

void foo () {}

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

并问为什么编译器不会抱怨这种情况。 这实际上是在这里解决的,但简而言之:C.2011仍然接受K&R C函数定义语法。 因此,虽然void foo() {}是一个不带参数的定义,但用于参数验证的原型与void foo();相同void foo(); ,因为空参数列表被解析为K&R。 强制进行适当参数检查的现代C语法将使用void foo(void) {}

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

15要兼容两种函数类型,两者都应指定兼容的返回类型.146)此外,...如果一种类型具有参数类型列表,另一种类型由包含(可能为空)标识符列表的函数定义指定两者都应在参数数量上达成一致,并且每个原型参数的类型应与从默认参数促销应用到相应标识符类型所产生的类型兼容。 (在确定类型兼容性和复合类型时,使用函数或数组类型声明的每个参数都被视为具有调整类型,并且使用限定类型声明的每个参数都被视为具有其声明类型的非限定版本。)

(6.2.7兼容型和复合型)

2涉及同一对象或功能的所有声明均应具有兼容类型; 否则, 行为未定义

因此,问题中显示的程序具有未定义的行为。 编译器可以像GCC那样发出诊断消息。

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

承诺在函数定义中,在声明列表中,你将有两个int类型的参数,但它们不存在。 在函数定义的情况下,空列表意味着函数不应该参数。 因此存在约束违规并且gcc抱怨是正确的。

这似乎是clang中的问题,至少不会产生警告。


行情:

章节§6.7,P4( 约束

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

然后,章节§6.7.6.3,P14,

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

因此,这构成了违反约束并且需要发出诊断。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM