【问题标题】:Default argument and parameter promotions in CC 中的默认参数和参数提升
【发布时间】:2020-09-02 05:45:04
【问题描述】:

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

§6.5.2.2 函数调用

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

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

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

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

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

现在我有一个非常愚蠢的疑问,如果函数声明和函数定义都不包括本段中提到的原型,那么他们在段落的最后三行中讨论的是哪些参数。 “提升后的参数”是什么意思,因为我只研究过参数提升。什么是“参数促销”?

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

【问题讨论】:

    标签: c standards undefined-behavior function-call promotions


    【解决方案1】:

    在 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
    }
    

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

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

    • charshort 晋升为 int
    • float 晋升为 double

    以这种方式定义的所有函数(K&R 风格)和可变参数都会发生这种情况。这样,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

    【讨论】:

    • 然后你也可以有short add_shorts(a, b) short a, b; { return a+b; },调用者仍然会提供可能提升的int值,但是函数定义决定在调用时转换它们。
    • 我明白你解释的一切,但我的疑问仍然存在。他们在段落的最后 3 行中讨论了哪些参数,因为函数声明和定义都没有原型。什么是参数提升?我知道参数会得到提升,但是这个参数提升是什么?
    • 注意:cppreference 不是智慧或真理的来源。
    • 如果一个函数没有原型,这意味着它是一个 K&R 风格的函数。我猜你以为它是一个没有参数的函数???
    • 是的,K&R 风格的函数还有可变参数。基本上,该标准有一种非常奇特的方式来表示它是 UB,它传递了函数不期望的东西(比如传递 int 而不是 double)。它是 UB,因为编译器无法知道函数期望什么(此类信息不包含在 K&R 函数和可变参数省略号中)。
    猜你喜欢
    • 2010-11-18
    • 2015-05-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-25
    • 1970-01-01
    相关资源
    最近更新 更多