C中的默认参数和参数提升

问题描述 投票:6回答:1

我当时正在研究默认参数提升问题,一度陷入困境。在C 2011(ISO / IEC 9899:2011)中,相关部分似乎是:

§6.5.2.2函数调用

¶6如果表示被调用的表达式函数的类型不包含原型,即整数对每个参数执行提升,并且具有类型float被提升为double。这些称为默认争论促销。如果参数个数不等于参数数量,行为是不确定的。如果功能是定义的类型包括原型,或者原型以省略号(,...)或参数的类型结尾升级后与参数类型不兼容,行为是不确定的。如果函数的类型定义为不包含原型,以及之后的参数类型促销与之后的参数不兼容升级,行为是不确定的,以下情况除外:

—一种提升类型是有符号整数类型,另一种提升类型是对应的无符号整数类型,值是两种类型均可表示;

-这两种类型都是指向合格或不合格版本的指针字符类型或无效。

在该段的最后三行中,讨论了在定义原型时不包括原型的函数类型。

它说如果升级后的参数类型与升级后的参数类型不兼容,则行为未定义

现在,我非常怀疑,如果函数声明和函数定义均未包含本段中提到的原型,那么在本段的后三行中讨论的是哪些参数。 “ 提升后的参数”的含义是什么,因为我只研究过论据提升。什么是“ 参数促销”?

您还可以举例说明最后提到的特殊情况。如果有人可以用一个正确的例子来解释这一点,那将是非常有意义的。

c standards undefined-behavior function-call promotions
1个回答
2
投票

在C标准化之前(也就是C89之前),功能的定义有所不同。 C11仍支持该样式以实现向后兼容。除非整个目的是要玩得开心,否则不要使用它:

int add_ints(); //forward-declaration has no parameters

add_ints(a, b)
//implicit type for return and parameters is int, this only works in pre-standard C or C89/C90
//int a, b; //remove this comment in C99/C11 for it to compile (also add return type int)
{
    return a + b; //side note: old K&R compilers required parantheses around the return expression
}

在某种程度上,这些函数的参数行为类似于varargs。调用者不知道函数需要什么参数(与varargs相同)。它能够传递给它任何参数以及任何数量的参数。但是,如果call语句中的参数数量与声明中的参数数量不匹配,则当然是未定义的行为。

当然,由此会产生一个问题。如果调用者想传递short,它将如何知道该函数是期望short(并直接传递)还是int(并需要转换)?它不能,所以达成了共识。已决定:

  • [charshort被提升为int] >>
  • [float被提升为double
  • 对于以这种方式定义的所有函数(K&R样式)和varargs参数,都会发生这种情况。这样,K&R函数将永远不会期望short参数,因此编译器将始终将short参数提升为int

当然,正如@aschepler所说,您仍然可以像这样定义函数:

short add_shorts(a, b)
    short a, b;
{
    return a + b;
}

这意味着参数首先被转换为int并传递给函数,然后函数才将其转换为short并添加它们。

请谨慎使用printf()之类的功能:

printf("%.f", 3); //passes an int: UB and also wrong answer (my compiler prints 0)
printf("%.f", 3.0); //correct
printf("%.f", (double)3); //correct

您可能实际上经常看到K&R函数,尤其是当作者不注意将void关键字添加到不带参数的函数中时:

int f1() //K&R function
{
    return 0;
}
int f2(void) //Standard function
{
    return 0;
}

int main(void) //Don't forget void here as well :P
{
    int a = f1(); //Returns 0
    int b = f2(); //Returns 0
    int c = f1(100); //UB - invalid number of parameters, in practice just returns 0 :)
    int d = f2(100); //Compiler error - parameter number/types don't match

    //A good compiler would give a warning for call #3, but mine doesn't :(
}

编辑:不知道为什么,但是cppreference将像f1()这样定义的函数分类为它们自己的函数类型(没有void的无参数),而不是K&R函数。我面前没有标准,但是即使标准说的是同一件事,它们的行为也应相同,并且具有我提到的历史。

Default argument promotions

Function declarations in C

© www.soinside.com 2019 - 2024. All rights reserved.