function() 中未指定的参数会发生什么?

Ard*_*der 11 c function

我一直在阅读的区别function()function(void)使用C,我才知道,

函数声明中的空参数列表表示该函数采用未指定数量的参数

所以我运行了这段代码

#include <stdio.h>

void fun();

int main(void)
{
    fun(12, 13.22, 1234567890987654321, "wow", 'c');
}

void fun()
{
    printf("What happened to those arguments?");
}
Run Code Online (Sandbox Code Playgroud)

我不明白为什么 C 允许这样做。到目前为止,我读过的所有与此相关的帖子都说使用它是不好的做法,它已经过时等。此外,从上面的代码中,我认为这些参数的类型也未指定。所以我只想知道“未指定类型的未指定参数”背后的原因:

  • 可以用这些参数做什么?

  • 是否可以在函数中访问这些参数?

Jon*_*ler 9

支持该符号的原因是历史性的。在第一个 C 标准(C89/C90)之前,你不能在 C 中使用原型;原型是标准 C 最大和最重要的特性之一。因此,所有函数声明都以“空括号”样式编写(当它们完全编写时;大多数返回的函数int根本没有声明)。voidC89/C90 中也添加了该类型,尽管在标准最终确定之前有些编译器支持它。

因为对于 C89/C90 的成功来说,现有代码大部分应该继续工作是至关重要的,所以标准必须允许空括号样式。因此,您的代码可能是用标准前的 C 编写的,如下所示:

#include <stdio.h>

int fun();  /* This declaration would probably have been absent */

int main(void)
{
    fun(12, 13.22, 1234567, "wow", 'c');
    return 0;   /* This was required until C99 to give reliable exit status */
}

fun(i, d, l, s, c)      /* No return type - implicitly returns int */
long l;                 /* Defined out of sequence - bad style, but legal */
char c;                 /* Passed as int; converted to char in function */
char *s;                /* Should define all pointer arguments */
double d;               /* No definition of i; it was an int by default */
{
    printf("This is what happened to those arguments:\n");
    printf("i = %d\n", i);
    printf("d = %f\n", d);
    printf("l = %ld\n", l);
    printf("s = [%s]\n", s);
    printf("c = %c\n", c);
    /* No return statement - don't use the value from the function */
}
Run Code Online (Sandbox Code Playgroud)

出于好奇:您可以省略char *s;函数定义中的这一行,它仍然编译并生成相同的输出。不过,尝试这样做是个坏主意。你可以替换线int fun();static fun();和代码编译干净时没有请求诊断。

如果您old31.c使用 GCC 9.3.0编译此文件 ( ),则即使现在您也不会收到警告:

$ gcc -std=c90 -o old31 old31.c
$
Run Code Online (Sandbox Code Playgroud)

您所写的示例绕过了向后兼容性规定。Usingvoid意味着它是新代码(它在许多预标准 C 编译器中无效,因为它使用了void)。并且新代码不应在没有充分理由的情况下利用向后兼容性条款。1991 年和本世纪都是如此(但在 1991 年,有更多充分的理由来利用向后兼容性条款)。良好的预标准代码通常会按使用顺序列出所有参数。省略的定义和乱序的定义并不完全令人满意。

你问:

  • 可以用这些参数做什么?

在问题的代码中,参数无能为力。调用者将值压入堆栈,并在函数返回时将它们弹出。被调用的函数不知道它们的存在并且不能对它们做任何事情。

  • 是否可以在函数中访问这些参数?

不——不使用任何标准机制。


dbu*_*ush 7

当参数列表为空时,函数声明和函数定义之间存在差异。

C 标准的第 6.7.6.3p14 节规定:

标识符列表仅声明函数参数的标识符。作为该函数定义的一部分的函数声明符中的空列表指定该函数没有参数。不属于该函数定义的函数声明符中的空列表指定不提供有关参数数量或类型的信息。

这意味着该声明:

void fun();
Run Code Online (Sandbox Code Playgroud)

Meansfun采用未知数量的参数。虽然这个定义:

void fun()
{
    printf("What happened to those arguments?");
}
Run Code Online (Sandbox Code Playgroud)

意味着不fun带参数。所以这个函数调用:

fun(12, 13.22, 1234567890987654321, "wow", 'c');
Run Code Online (Sandbox Code Playgroud)

无效并调用未定义行为,因为调用中的参数数量与实际参数数量不匹配。这在关于函数调用运算符的第 6.5.2.2p6 节中有详细说明()

如果表示被调用函数的表达式的类型不包含原型,则对每个参数执行整数提升,并将具有类型的参数float提升为double。这些称为默认参数提升。如果参数数量不等于参数数量,则行为未定义。如果函数定义的类型包含原型,并且原型以省略号 (, ...) 或者提升后的参数类型与参数类型不兼容,则行为未定义。如果函数定义的类型不包含原型,并且提升后的参数类型不兼容对于提升后的参数,行为未定义,但以下情况除外:

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

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

至于为什么允许这样做,这是可以追溯到 C 的预标准化版本的遗留行为,其中默认的变量类型和函数的返回类型int以及声明函数的方法与现在不同。