简体   繁体   English

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

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

Given (simplified) code snippet: 给定(简化)代码片段:

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

}

and command-line options (though, as I checked they are not important): 和命令行选项(但是,因为我检查它们并不重要):

-x c -std=c11 -pedantic -Wall

gcc 7.2 fails to compile it with following error message: gcc 7.2无法编译它,并显示以下错误消息:

error: number of arguments doesn't match prototype 错误:参数数量与原型不匹配

while clang 4.0 translates it without any complaints. 虽然clang 4.0翻译它没有任何投诉。

Which implementation is correct according to C Standard? 根据C标准,哪种实施方法是正确的? Is it valid that old-style definition "cancels" previous prototype? 旧式定义“取消”以前的原型是否有效?

(C11, 6.7p4 Constraints) "All declarations in the same scope that refer to the same object or function shall specify compatible types" (C11,6.7p4约束)“在同一范围内引用同一对象或函数的所有声明都应指定兼容类型”

and

(C11, 6.7.6.3p14) "An identifier list declares only the identifiers of the parameters of the function. An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters. [...]" (C11,6.7.6.3p14)“标识符列表仅声明函数参数的标识符。函数声明符中的空列表是该函数定义的一部分,指定该函数没有参数。[.. 。]”

My opinion is constraint of 6.7p4 is violated and diagnostic has to be issued. 我认为违反6.7p4的约束并且必须发布诊断。

EDIT: 编辑:

as pointed out by @hvd it is actually not correct. 正如@hvd指出的那样,实际上并不正确。 6.7.6.3p14 does not mean void foo() {} provides a prototype for foo as per DR#317 . 6.7.6.3p14并不意味着void foo() {}根据DR#317foo提供原型。 In that sense, the 6.7p4 constraint is not violated and so clang is right not to complain. 从这个意义上说,6.7p4约束没有被违反,所以clang是不对的抱怨。

Disclaimer: I am not a , but I play one on . 免责声明:我不是 ,但我在上玩一个。

If the compiler does not issue a diagnostic, it would be non-conforming, and could be considered a bug if the compiler claims to be conforming. 如果编译器没有发出诊断,那么它将是不符合的,如果编译器声称符合要求,则可能被视为错误。

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

An identifier list declares only the identifiers of the parameters of the function. 标识符列表仅声明函数参数的标识符。 An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters. 函数声明符中的空列表是该函数定义的一部分,指定该函数没有参数。 The empty list in a function declarator that is not part of a definition of that function specifies that no information about the number or types of the parameters is supplied. 函数声明符中的空列表不是该函数定义的一部分,它指定不提供有关参数数量或类型的信息。

Thus, the definition of foo specifies no parameters, while the declaration of foo earlier specified two parameters. 因此, foo的定义没有指定参数,而foo的声明早先指定了两个参数。

C.2011§6.7.6.3¶15: C.2011§6.7.6.3¶15:

For two function types to be compatible, both shall specify compatible return types. 要使两种函数类型兼容,两者都应指定兼容的返回类型。 146) Moreover, the parameter type lists, if both are present , shall agree in the number of parameters and in use of the ellipsis terminator; 146)此外,参数类型列表( 如果两者都存在 )应在参数数量和省略号终止符的使用中一致; corresponding parameters shall have compatible types. 相应的参数应具有兼容的类型。
146) If both function types are ''old style'', parameter types are not compared. 146)如果两种函数类型都是“旧样式”,则不比较参数类型。

Thus, the two declarators of foo are not compatible. 因此, foo的两个声明foo不兼容。
Dang! 党! From @hvd's comment : 来自@ hvd的评论

It's well-established that void foo() does not provide a prototype, even in a definition. 已经确定void foo()不提供原型,即使在定义中也是如此。 There was a DR that answered this explicitly. 有一个DR明确地回答了这个问题。 The type of foo in that definition is void foo() , not void foo(void) , and void foo() and void foo(int, int) are compatible types. 该定义中的foo类型为void foo() ,而不是void foo(void)void foo()void foo(int, int)是兼容类型。 This answer is incorrect. 这个答案是不正确的。

The emphasized part of the text above from the standard is the loophole that allows for the disagreement in number of arguments, but compatible types. 标准中上面强调的部分是漏洞,它允许参数数量不一致,但兼容类型。 Although the function definition specifies a function that takes no arguments, since the parameter type list is actually missing, there is actually no incompatibility between the type of foo in its function prototype and the type of foo in the function definition. 虽然功能定义指定一个函数,它不带任何参数,因为参数类型列表实际上是缺少,但是实际上的类型之间没有不兼容foo在其函数原型和类型foo的函数定义。

Thus, clang 4.0 seems to have it right, since there is no constraint violation. 因此,clang 4.0似乎是正确的,因为没有约束违规。

My original argument becomes invalid, so editing out that part of my original answer. 我原来的论点变得无效,所以编辑我原来答案的那一部分。


In comments you actually presented the following example: 在评论中,您实际呈现了以下示例:

void foo () {}

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

And asked why the compiler does not complain for this case. 并问为什么编译器不会抱怨这种情况。 This is actually addressed here , but in a nutshell: C.2011 still accepts K&R C function definition syntax. 这实际上是在这里解决的,但简而言之:C.2011仍然接受K&R C函数定义语法。 So, while void foo() {} is a definition that takes no arguments, the prototype that is used for argument validation is the same as void foo(); 因此,虽然void foo() {}是一个不带参数的定义,但用于参数验证的原型与void foo();相同void foo(); , because the empty argument list is parsed as K&R. ,因为空参数列表被解析为K&R。 The modern C syntax to force proper argument checking would be to use void foo(void) {} instead. 强制进行适当参数检查的现代C语法将使用void foo(void) {}

From the C Standard (6.7.6.3 Function declarators (including prototypes)) 来自C标准(6.7.6.3函数声明符(包括原型))

15 For two function types to be compatible, both shall specify compatible return types.146) Moreover, ... If one type has a parameter type list and the other type is specified by a function definition that contains a (possibly empty) identifier list, both shall agree in the number of parameters, and the type of each prototype parameter shall be compatible with the type that results from the application of the default argument promotions to the type of the corresponding identifier. 15要兼容两种函数类型,两者都应指定兼容的返回类型.146)此外,...如果一种类型具有参数类型列表,另一种类型由包含(可能为空)标识符列表的函数定义指定两者都应在参数数量上达成一致,并且每个原型参数的类型应与从默认参数促销应用到相应标识符类型所产生的类型兼容。 (In the determination of type compatibility and of a composite type, each parameter declared with function or array type is taken as having the adjusted type and each parameter declared with qualified type is taken as having the unqualified version of its declared type.) (在确定类型兼容性和复合类型时,使用函数或数组类型声明的每个参数都被视为具有调整类型,并且使用限定类型声明的每个参数都被视为具有其声明类型的非限定版本。)

And (6.2.7 Compatible type and composite type) (6.2.7兼容型和复合型)

2 All declarations that refer to the same object or function shall have compatible type; 2涉及同一对象或功能的所有声明均应具有兼容类型; otherwise, the behavior is undefined 否则, 行为未定义

Thus the shown program in the question has undefined behavior. 因此,问题中显示的程序具有未定义的行为。 The compiler may issue a diagnostic message as GCC did. 编译器可以像GCC那样发出诊断消息。

I do not have a quote from a standard 我没有标准的引用 ( edit: Refer C11 , chapter 6.7.6.3/P14 ), but as per my understanding, gcc is right to shout, as you're contradicting yourself. 编辑:参见C11 ,章节6.7.6.3/P14 ),但根据我的理解, gcc是正确的,因为你自相矛盾。

You promised that in the function definition, in the declaration-list, you will have two parameters of type int , but they are not there. 承诺在函数定义中,在声明列表中,你将有两个int类型的参数,但它们不存在。 In case of a function definition, and empty list means that function should take no parameter. 在函数定义的情况下,空列表意味着函数不应该参数。 So there is a constraint violation and gcc is right to complain. 因此存在约束违规并且gcc抱怨是正确的。

It seems this is a problem in clang that is does not produce a warning at least. 这似乎是clang中的问题,至少不会产生警告。


Quotes: 行情:

Chapter §6.7, P4 ( Constraints ) 章节§6.7,P4( 约束

All declarations in the same scope that refer to the same object or function shall specify compatible types. 引用同一对象或函数的同一范围内的所有声明都应指定兼容类型。

then, chapter §6.7.6.3, P14, 然后,章节§6.7.6.3,P14,

An identifier list declares only the identifiers of the parameters of the function. 标识符列表仅声明函数参数的标识符。 An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters. 函数声明符中的空列表是该函数定义的一部分,指定该函数没有参数。 The empty list in a function declarator that is not part of a definition of that function specifies that no information about the number or types of the parameters is supplied. 函数声明符中的空列表不是该函数定义的一部分,它指定不提供有关参数数量或类型的信息。

So, this constitutes a constraint violation and warrant a diagnostic to be emitted. 因此,这构成了违反约束并且需要发出诊断。

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

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