C函数调用中的默认参数提升

C函数调用中的默认参数提升

设置

对于C中调用函数时的默认参数升级,我有几个问题。这里的6.5.2.2节“函数调用”第6、7和8段来自C99标准(Pdf)(为便于阅读,增加并细分为清单):

第6段

  1. 如果表示被调用函数的表达式具有以下类型

    不包括原型

    ,则对每个参数和具有类型的参数执行整数提升。

    float

    升为

    double

    ..这些叫做

    默认参数提升.

  2. 如果参数不等于参数,则行为未定义。
  3. 如果函数是用以下类型定义的

    包括一个原型

    ,或者原型以省略号结尾(

    , ...

    )或者升级后的参数类型与参数的类型不兼容,则行为是未定义的。
  4. 如果函数是用以下类型定义的

    不包括原型

    ,而且升级后的参数类型与升级后的参数类型不兼容,除下列情况外,行为未定义:
    • 一种提升类型是有符号整数类型,另一种提升类型是对应的无符号整数类型,该值在这两种类型中都是可表示的;
    • 这两种类型都是指向字符类型或

      void.

第7段

  1. 如果表示被调用函数的表达式具有以下类型

    包括一个原型

    ,参数被隐式转换,就像通过赋值一样,转换为相应参数的类型,将每个参数的类型作为其声明类型的非限定版本。
  2. 函数原型声明器中的省略符号将导致在上次声明参数之后停止参数类型转换。

    默认的参数提升是对尾随参数执行的。

第8段

  1. 不隐式执行其他转换;特别是,参数的数量和类型不能与函数定义中的参数进行比较。

    不包括函数原型声明器。.

我所知道的

  • 这个

    默认参数提升

    char

    short

    int/unsigned int

    float

    double

  • 变量函数的可选参数(如

    printf

    )是否受默认参数提升的限制。

作为记录,我的理解是功能原型这是:

void func(int a, char b, float c);  // Function prototypevoid func(int a, char b, float c) { /* ... */ }  // Function definition

问题

这一切都让我很难受。以下是我的一些问题:

  • 原型函数和非原型函数的行为真的有很大的不同吗,比如在默认升级和隐式转换方面?
  • 默认参数提升何时发生?总是这样吗?或者仅仅是在特殊情况下(比如各种函数)?它是否取决于一个函数是否是原型的?


德玛西亚99
浏览 508回答 3
3回答

森栏

UPDATED AProgrammer的回答-这些才是真正的商品。对于那些想知道为什么情况是这样的:在1988年以前的黑暗时代,在经典的“K&R”C中没有函数原型这样的东西,默认的论点推广是因为(A)基本上是“免费”的,因为在寄存器中放置一个字节比在寄存器中放一个单词要花费更多的钱,以及(B)减少参数传递中可能出现的错误。第二个原因并没有完全消除它,这就是为什么在ANSI C中引入功能原型是C语言中最重要的变化。至于默认促销何时开始:当参数的预期类型为未知数,也就是说,当没有原型的时候,或者争论是不同的。

跃然一笑

(非变量)参数与原型函数的参数转换为相应的类型,这种类型可以是char、Short、Float。没有原型和可变参数的函数的参数受默认参数提升的影响。如果使用Prototype定义函数并使用它而不使用Prototype,反之亦然,并且它具有char、Short或Float类型的参数,那么在运行时可能会出现问题。如果提升类型与读取参数列表时使用的类型不匹配,则变量函数将遇到相同的问题。示例1:用原型定义函数并不使用它时的问题。定义cvoid f(char c){    printf("%c", c);}使用.cvoid f();int main(){    f('x');}可能会失败,因为一个int将被传递,并且函数需要一个char。示例2:在没有原型的情况下定义函数并将其与原型一起使用时的问题。定义cvoid f(c)    char c;{    printf("%c", c);}(这是一种很老套的定义)使用.cvoid f(char c);int main(){    f('x');}可能会失败,因为需要一个int,但会传递一个字符。注意:您会注意到,标准库中的所有函数都有默认升级导致的类型。因此,当添加原型时,它们不会在转换过程中引起问题。

绝地无双

您的困惑源于对术语的非常轻微的误解-声明和定义都可以包括原型(或不包括):void func(int a, char b, float c);那是一个函数声明包括一个原型。void func(int a, char b, float c) { /* ... */ }那是一个函数定义包括一个原型。“原型”和“非原型”只是函数的属性。类型,而声明和定义都引入了函数的类型。因此,您可以在没有原型的情况下进行声明:void func();或者,您可以使用没有原型的定义(K&R&C风格):void func(a, b, c)     int a;     char b;     float c;{ /* ... */ }
打开App,查看更多内容
随时随地看视频慕课网APP