可变参数列表是通过stdarg.h内的宏来实现的:

类型 va_list

三个宏:

  va_start

  va_arg

  va_end

我们可以声明一个va_list变量,与这三个宏配合使用。

可变参数必须要有一个命名参数,因为可变参数是通过栈来实现的,函数中的最右边的参数最先入栈。

void function(int a, int b, int c)
{
int d;
...
}

其栈结构为

0x1ffc-->d

0x2000-->a

0x2004-->b

0x2008-->c

栈的空间是连续的,所以函数第一个必须是命名参数,这样就可以通过第一个参数来寻址,根据类型所占字节偏移,获取后续的所有可变参数值。

下面是利用可变参数计算平均值函数:

#include <stdarg.h>

float average(int n_num, ...)
{
int count;
float sum = 0; //var_arg是一个指针,通过va_start指向第一个命名参数位置
va_list var_arg;
va_start(var_arg, n_num); for (count = 0; count < n_num; count++) {
//va_arg第二个参数是类型,根据类型来偏移获取参数值
sum += va_arg(var_arg, int);
} //让指针指向NULL,不在指向堆栈
va_end(var_arg); return sum / n_num;
}

所以这些宏存在两个问题,一来无法确定参数数量,因为不同类型所占空间不同,二来无法确定类型,printf函数的类型是通过字符串中的格式字符串来提取类型实现的。

参考:http://blog.chinaunix.net/uid-20545038-id-1648593.html

     http://www.cnblogs.com/cpoint/p/3368993.html

C和指针 第七章 可变参数的更多相关文章

  1. C和指针 第七章 习题

    7.1 hermite递归函数 int hermite(int n, int x) { if (n <= 0) { return 1; } if (n == 1) { return 2 * x; ...

  2. C和指针第七章第五题

    实现一个简化的printf函数,能够处理%d,%f,%s,%c等格式. /*************************************************************** ...

  3. C和指针 第七章 函数递归与迭代

    C语言通过运行时堆栈支持递归函数的实现,递归函数时直接或者间接调用自身的函数,经常有人拿斐波那契实现当做递归的实现,然后这样做效率并不高. n < 1;  Fib(1) =1 n = 2;  F ...

  4. 【转载】va_list 可变参数 简介 va_copy vprintf

    [说明]本文转载自 smart 的文章 http://blog.sina.com.cn/s/blog_590be5290100qhxr.html  及百度百科 va_list是一个宏,由va_star ...

  5. C++可变参数列表处理宏va_list、va_start、va_end的使用

      VA_LIST是在C语言中解决变参问题的一组宏他有这么几个成员: 1)va_list型变量: #ifdef     _M_ALPHA typedef    struct{ char* a0; /* ...

  6. 【转】C++可变参数列表处理宏va_list、va_start、va_end的使用

    VA_LIST是在C语言中解决变参问题的一组宏他有这么几个成员: 1)va_list型变量: #ifdef     _M_ALPHA typedef    struct{ char* a0; /*po ...

  7. 可变参数以及stdcall

    void event_warnx(const char *fmt, ...) EV_CHECK_FMT(1,2); #define EV_CHECK_FMT(a,b) __attribute__((f ...

  8. C++逆向 可变参数Hook

    目录 C++逆向 可变参数Hook 0x00 前言: 0x01 C++可变参数: 可变参数简介 可变参数代码实战 0x02 逆向分析C++可变参数原理 0x03 printf Hook实战 Pwn菜鸡 ...

  9. C和指针 (pointers on C)——第七章:函数(上)

    第七章 函数 这一章对于有一定C的基础的人有一定优秀代码风格的人来说,并非非常虐.关于stdarg宏可能有些陌生.它负责可变參数列表的定义. 总结: 新式风格和旧式风格就不要提了.八百年前的事情. 函 ...

随机推荐

  1. 第47课 Qt中的调色板

    1. QPalette类 (1)QPalette类提供了绘制QWidget组件的不同状态所使用的颜色. (2)QPalette对象包含了3个状态的颜色描述 ①激活颜色组(Active):组件获得焦点使 ...

  2. JavaScript模板引擎artTemplate.js——为什么使用模板引擎?

    作为一个工作一年的菜鸟,在公司做了几个外包项目,也接触到了不同形式的web开发.其实也没多少,就是javaweb开发和HTML5移动开发,这两者在页面展示的时候的解决方案还是有所不同的. 1.vo+e ...

  3. 【C#】C# 队列,

    1.队列[先进先走,Dequeue():删除第一个并返回删除的这个],泛型[不确定参数的类型],

  4. Android studio2.2 ndk 错误 :format not a string literal and no format arguments!

    在Android Studio2.2 进行NDK编程,在对*char 字符串 进行日志输出时,报错: error: format not a string literal and no format  ...

  5. ASP.NET Identity系列教程(目录)

    $(document).ready(function(){ $("#hide").click(function(){ $(".en").hide(); }); ...

  6. jquery 使用方法

      jQuery是目前使用最广泛的javascript函数库.据统计,全世界排名前100万的网站,有46%使用jQuery,远远超过其他库.微软公司甚至把jQuery作为他们的官方库.对于网页开发者来 ...

  7. Python笔记(2)函数

    python中一切皆对象,函数也看做对象.函数被函数名所引用,但是同样的他也可以被其他标识符所引用,可以作为参数传递. def f(): return "hi" 可见a引用了函数返 ...

  8. PHPExcel读取excel文件

    <?php set_time_limit(0); $dir = dirname(__FILE__);//当前脚本所在路径 require $dir."/PHPExcel_1.8.0/C ...

  9. Git的使用

    1.从Git服务器上获取项目   2.提交我的修改项目 3.发布新版本 4.修复bug

  10. TYVJ P1080 N皇后

    描述 检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行.每列只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子. 列号  1  2  3  4  5  6 -- ...