C 中的默认参数和参数提升 [英] Default argument and parameter promotions in C

查看:21
本文介绍了C 中的默认参数和参数提升的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究默认参数提升,但有一次被卡住了.在 C 2011 (ISO/IEC 9899:2011) 中,相关部分似乎是:

I was studying about default argument promotions and got stuck at one point. In C 2011 (ISO/IEC 9899:2011), the relevant part seem to be:

§6.5.2.2 函数调用

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

¶6 If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions. If the number of arguments does not equal the number of parameters, the behavior is undefined. If the function is defined with a type that includes a prototype, and either the prototype ends with an ellipsis (, ...) or the types of the arguments after promotion are not compatible with the types of the parameters, the behavior is undefined. If the function is defined with a type that does not include a prototype, and the types of the arguments after promotion are not compatible with those of the parameters after promotion, the behavior is undefined, except for the following cases:

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

— one promoted type is a signed integer type, the other promoted type is the corresponding unsigned integer type, and the value is representable in both types;

——这两种类型都是指向 a 的限定或非限定版本的指针字符类型或void.

— both types are pointers to qualified or unqualified versions of a character type or void.

在段落的最后三行中,它讨论了定义时不包含原型的函数类型.

In the last three lines of paragraph it talks about the function type that does not include a prototype while defining it.

表示如果提升后的参数类型与提升后的参数类型不兼容,则行为未定义.

现在我有一个非常愚蠢的疑问,如果函数声明和函数定义都没有包含本段中提到的原型,那么他们在段落的最后三行中谈论的是哪些参数.在这里参数提升后"是什么意思,因为我只研究了参数提升.什么是参数提升"?

Now i have a very silly doubt that if both the function declaration and function definition does not include a prototype as mentioned in this paragraph, so about which parameters they are talking about in last three lines of paragraph. And what is the meaning of "parameters after promotion" here as i have only studied about argument promotions. What is "parameter promotions"?

你还可以举出最后提到的例外情况的例子.如果有人能用一个适当的例子来解释这一点,那将是非常可观的.

Also can you give example of the exceptional cases mentioned in the last. If someone can explain this with a proper example that would be really appreciable.

推荐答案

在 C 被标准化之前(也就是在 C89 之前),函数的定义是不同的.为了向后兼容,C11 中仍然支持该样式.除非整个目的是为了玩得开心,否则不要使用它:

Before C was standardized (aka before C89), functions were defined differently. The style is still supported in C11 for backwards-compatibility. Don't use it unless the whole purpose is to have fun:

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
}

在某种程度上,这些函数的参数表现得像可变参数.调用者不知道函数期望什么参数(与可变参数相同).它能够向它传递任何参数和任意数量的参数.但是,如果调用语句中的参数数量与声明中的参数数量不匹配,这当然是未定义的行为.

In a way, these functions have parameters that behave like varargs. The caller doesn't know what parameters the function expects (same as with varargs). It is able to pass it any parameters and any number of them. However, it is of course undefined behavior if the number of parameters in the call statement doesn't match the number of parameters in the declaration.

当然,由此产生了一个问题.如果调用者想要传递一个short,它如何知道函数是期待一个short(并直接传递它)还是一个int(并且需要转换它)?它不能,因此达成了共同点.已决定:

Of course, there is a problem that arises from this. If the caller wants to pass a short, how will it know whether the function is expecting a short (and pass it directly) or an int (and needs to convert it)? It cannot, so a common ground was reached. It has been decided that:

  • charshort 被提升为 int
  • float 被提升为 double
  • char and short get promoted to int
  • float gets promoted to double

这种情况发生在所有以这种方式定义的函数(K&R 风格)和可变参数参数中.这样,K&R 函数将永远不会期望 short 参数,因此编译器总是将 short 参数提升为 int.

This happens for all functions defined this way (K&R style) and for varargs parameters. This way, a K&R function will never expect a short parameter, thus the compiler will always promote short parameters to int.

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

Of course, as @aschepler said, you can still define the function like:

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

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

This means that the parameters are first converted to int and passed to the function and only then does the function convert them to short and add them.

小心像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 关键字添加到不带参数的函数中:

You may actually see K&R functions quite often, especially if the author didn't pay attention to add the void keyword to a function that takes no parameters:

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 函数.我面前没有标准,但即使标准说同样的话,他们也应该表现得一样,他们有我提到的历史.

Not sure why, but cppreference classifies functions defined like f1() as their own type of function (parameter-less without void), instead of K&R functions. I don't have the standard in front of me, but even if the standard says the same thing, they should behave the same and they have the history I mentioned.

默认参数提升

C 中的函数声明

这篇关于C 中的默认参数和参数提升的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆