为了账号安全,请及时绑定邮箱和手机立即绑定

在C中使用varargs的示例

在C中使用varargs的示例

C
qq_遁去的一_1 2019-12-16 13:12:42
在这里,我找到了一个示例,说明如何在C中使用varargs。#include <stdarg.h>double average(int count, ...){    va_list ap;    int j;    double tot = 0;    va_start(ap, count); //Requires the last fixed parameter (to get the address)    for(j=0; j<count; j++)        tot+=va_arg(ap, double); //Requires the type to cast to. Increments ap to the next argument.    va_end(ap);    return tot/count;}我只能在某种程度上理解此示例。我不清楚我们为什么使用va_start(ap, count);。据我了解,通过这种方式,我们将迭代器设置为其第一个元素。但是,为什么默认情况下不将其设置为开头?我不清楚为什么我们需要给出count一个论据。C不能自动确定参数的数量吗?我不清楚我们为什么使用va_end(ap)。它会发生什么变化?是否将迭代器设置为列表的末尾?但是不是通过循环将其设置为列表的末尾吗?而且,为什么我们需要它?我们不再使用ap;我们为什么要更改它?
查看完整描述

3 回答

?
万千封印

TA贡献1891条经验 获得超3个赞

但是,为什么默认情况下不将其设置为开头?


也许是由于历史原因导致的,当时编译器还不够聪明。可能是因为您可能拥有一个varargs函数原型,而该原型实际上并不在乎varargs,而在该特定系统上设置varargs恰好很昂贵。可能是因为va_copy您要执行更复杂的操作,或者您想多次重新启动参数并多次调用va_start。


简短的版本是:因为语言标准是这样说的。


第二,对我来说不清楚,为什么我们需要计数。C ++不能自动确定参数的数量吗?


那不是全部count。它是函数的最后一个命名参数。va_start需要它来找出可变参数在哪里。这很可能是由于旧编译器的历史原因所致。我不明白为什么今天不能以不同的方式实现它。


问题的第二部分:不,编译器不知道向该函数发送了多少个参数。它甚至可能不在同一编译单元或同一程序中,并且编译器也不知道该函数将如何被调用。想象一个具有varargs函数的库,例如printf。当您编译libc时,编译器不知道何时以及如何调用程序printf。在大多数ABI上(ABI是如何调用函数,如何传递参数的约定,等等),无法找出函数调用获得了多少个参数。将这些信息包含在函数调用中非常浪费,而且几乎不需要。因此,您需要一种方法来告诉varargs函数有多少个参数。存取中va_arg 未定义的行为超出了实际传递的参数数量。


然后我不清楚我们为什么要使用va_end(ap)。它会发生什么变化?


在大多数架构va_end上,没有任何相关的事情。但是有些架构具有传递自变量语义的复杂参数,va_start甚至可能潜在地va_end分配内存,那么您就需要释放该内存。


这里的简短版本也是:因为语言标准是这样说的。



查看完整回答
反对 回复 2019-12-17
?
慕容3067478

TA贡献1773条经验 获得超3个赞

va_start初始化变量参数列表。您总是将最后一个命名函数参数作为第二个参数传递。这是因为您需要提供有关堆栈中变量自变量开始的位置的信息,因为自变量被压入堆栈,并且编译器无法知道变量自变量列表的开始位置(没有区别)。

至于va_end,它用于释放在va_start调用期间分配给变量参数列表的资源。


查看完整回答
反对 回复 2019-12-17
  • 3 回答
  • 0 关注
  • 355 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信