为什么C中不允许使用void f(...)?

Raj*_*pal 6 c variable-length

为什么C不允许具有可变长度参数列表的函数,例如:

void f(...)
{
    // do something...
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*sop 10

我认为varargs函数必须具有命名参数的要求的动机是为了统一va_start.为了便于实现,请va_start获取最后一个命名参数的名称.使用典型的varargs调用约定,并且根据存储的方向参数,va_arg将在地址处找到第一个vararg,(&parameter_name) + 1或者(first_vararg_type*)(&parameter_name) - 1加上或减去一些填充以确保对齐.

我认为语言无法支持没有命名参数的varargs函数有任何特殊原因.va_start在这样的函数中必须有一种替代形式,它必须直接从堆栈指针获取第一个vararg(或者是帧指针的迂腐,这实际上是堆栈指针对函数的作用)条目,因为函数中的代码可能已经移动了sp,因为函数条目).原则上这是可能的 - 任何实现都应该在某种程度上以某种方式访问​​堆栈[*] - 但对于某些实现者来说可能会很烦人.一旦你知道的可变参数调用约定可以一般实行va_宏没有任何其他特定于实现的知识,这需要知道如何在调用的参数直接得到.我之前在仿真层中实现了那些varargs宏,它会让我生气.

此外,没有命名参数的varargs函数没有很多实际用途.varargs函数没有语言特性来确定变量参数的类型和数量,因此被调用者必须知道第一个vararg的类型才能读取它.所以你不妨把它作为一个带有类型的命名参数.在printf和朋友中,第一个参数的告诉函数varargs 的类型是什么,以及有多少类型.

我想在理论上,被调用者可以看一些全局来弄清楚如何读取第一个参数(以及是否有一个),但这是非常讨厌的.我当然不会支持这一点,并且添加一个va_start额外的实施负担的新版本正在我的方式.

[*]或者如果实现不使用堆栈,则使用它来代替传递函数参数.


Ale*_*s G 9

使用可变长度参数列表,您必须声明第一个参数的类型 - 这是语言的语法.

void f(int k, ...)
{
    /* do something */
}
Run Code Online (Sandbox Code Playgroud)

会工作得很好.然后,你必须使用va_list,va_start,va_end等里面的功能访问各个参数.

  • +1是实际阅读问题的人的唯一答案,并解释了为什么不允许这样做. (3认同)
  • imo"因为它的语法"不是解释,只是对事实的陈述. (3认同)
  • @Aleks:你的所有答案都只是信息,它是C中var arg列表用法的定义,而不是我的问题的答案.C++支持void f(...); 没问题! (2认同)