可变参数的函数与宏

1、可变参数的函数

<stdarg.h>头文件中定义了一些宏,用于可变参数的函数,如下

va_list:这种类型声明局部状态变量,假设变量名为va(用于下面的描述),用于遍历函数。

va_start:这个宏初始化状态变量va,要先调用之后才能调用va_arg与va_end。

va_arg:这个宏返回参数表中下一个参数的值,将内部指针(在va中)移到下一个参数,下一个参数的类型要用type指定,使va_arg能够计算其在堆栈中的长度,调用va_start之后第一次调用va_arg返回第一个可变参数的值。

va_end:这个函数或宏在用va_arg读取所有参数之后调用,对va进行必要的整理操作。

va_copy:C99中新增,这个宏在dest中复制src的当前状态,在参数表中生成第二个指针,然后可以独立对src与dest采用va_arg,dest中要像src中一样调用va_end。

下面是一个简单的了例子:

#include <stdio.h>
#include <stdarg.h>

void printargs(int num, ...)
{
    va_list va;
    va_start(va, num);
    int index = 0;
    int value = num;
    while (1) {
        printf("args[%d] = %d\n", index, value);
        if ((value = va_arg(va, int)) == 0) {
            break;
        }
        index++;
    }
    va_end(va);
}

int main(void)
{
    printargs(1, 2, 3, 4, 5, 0);

    return 0;
}

输出结果如下:

    args[0] = 1
    args[1] = 2
    args[2] = 3
    args[3] = 4
    args[4] = 5

2、可变参数的宏

可变参数的宏,有两种形式,如下例子:

#define MultiArgs(format, ...) printf(format, __VA_ARGS__)
#define PrintArgs(format, args...) printf(format, ##args)

MultiArgs("%s, %s\n", "hello", "world!"); // hello, world!
PrintArgs("%s, %s\n", "hello", "c language!"); // hello, c language!

需要注意的是,上面两种参数宏的参数列表形式的差异,PrintArgs宏的arg参数后面不能有逗号。

时间: 2024-10-12 12:21:35

可变参数的函数与宏的相关文章

C语言利用va_list、va_start、va_end、va_arg宏定义可变参数的函数

在定义可变参数的函数之前,先来理解一下函数参数的传递原理: 1.函数参数是以栈这种数据结构来存取的,在函数参数列表中,从右至左依次入栈. 2.参数的内存存放格式:参数的内存地址存放在内存的堆栈段中,在执行函数的时候,从最后一个(最右边)参数开始入栈.因此栈底高地址,栈顶低地址,举个例子说明一下: void test(int a, float b, char c); 那么,在调用test函数的时候,实参char c先进栈,然后是float b,最后才是int a,因此在内存中变量的存放次序是c->

Objective-C可变参数的函数实现

1.前言 相信接触过OC的对NSLog都很熟悉,细心查看NSLog的原始定义,会发现,他的原型如下: FOUNDATION_EXPORT void NSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2); 路径在:OS X version/Frameworks/Foundation/NSObjCRuntime.h 注意到参数最后的...,这里是可变参数.这样,在调用时就可以根据需要传入相应个数的参数了. PS:其实在C#中也有params指定可变

C语言中可变参数的函数(三个点,“...”)

C语言中可变参数的函数(三个点,"...") 本文主要介绍va_start和va_end的使用及原理. 在以前的一篇帖子Format MessageBox 详解中曾使用到va_start和va_end这两个宏,但对它们也只是泛泛的了解. 介绍这两个宏之前先看一下C中传递函数的参数时的用法和原理: 1.在C中,当我们无法列出传递函数的所有实参的类型和数目时,可以用省略号指定参数表 void foo(...); void foo(parm_list,...); 这种方式和我们以前认识的不大

可变参数的函数(variadic function)的陷阱

1,介绍variadic function 可变参数的函数就是参数数量可以改变的函数.例如printf(): int printf(const char *format, ...); printf("%d%s\n",i,s); C语言之所以可以支持可变参数函数,一个重要的原因是C调用规范中规定C语言函数调用时,参数是从右向左压入栈的:这样一个函数实现的时候,就无需关心调用他的函数会传递几个参数过来,而只要关心自己用到几个:例子: #include<stdarg.h> voi

可变参数列表函数实现

如题 我们在写可变参数列表函数之前,先来了解一下什么是可变参数列表函数. 我们在c语言编程中有时会遇到 一些参数个数可变的函数,例如printf()函数,其函数原型为: int printf(const char* format,-): 它除了有一个参数format固定以外,后面跟的参数个数和类型是可变的(用三个点"..."做参数占位符),实际调用时可以有以下的形式: printf("%d",i); printf("%s",s); printf(

python可变参数调用函数问题

一直使用python实现一些想法,最近在使用python的过程中出现这样一个需求,定义了一个函数,第一个是普通参数,第二个是默认参数,后面还有可变参数,在最初学习python的时候,都知道非关键字可变参数和关键字可变参数两种,调用的方式也非常多种多样,这里主要提出一个比较隐含的问题,并将各种可能出现的情况进行了探讨. 函数声明格式 python虽然不支持函数重载,但是通过对函数参数的众多特性的支持基本弥补了.函数声明的通式如下: def func(argv1,argv2...[,argv_d =

可变参数的函数

比如对于printf()函数,其参数就是可变的:int printf( const char* format, ...); 在函数内部我们使用va_start.va_arg.va_end这几个宏来获取实参,示例代码如下: #include <cstdio> #include <iostream> #include <cstdarg> using namespace std; void TestFun(int i, ...) { va_list ap; va_start(

编写一个可变参数的C函数——头文件stdarg.h中宏va_start ,va_arg和va_end的应用

我们在C语言编程中会遇到一些参数个数可变的函数,例如printf()这个函数,它的定义是这样的:int printf( const char* format, ...);它除了有一个参数format固定以外,后面跟的参数的个数和类型是可变的,例如我们可以有以下不同的调用方法:printf("%d",i);printf("%s",s);printf("the number is %d ,string is:%s", i, s);究竟如何写可变参数的

C语言可变参数函数实现原理

一.可变参数函数实现原理 C函数调用的栈结构: 可变参数函数的实现与函数调用的栈结构密切相关,正常情况下C的函数参数入栈规则为__stdcall, 它是从右到左的,即函数中的最右边的参数最先入栈. 本文地址:http://www.cnblogs.com/archimedes/p/variable-parameter.html,转载请注明源地址. 例如,对于函数: void fun(int a, int b, int c) { int d; ... } 其栈结构为 0x1ffc-->d 0x200