#include<stdlib.h>
#include<stdio.h>
#include<stdarg.h>/*
1. 使用va_list va_start va_arg va_end实现可变参数
*/
void simple_va_fun(int i, ...) {va_list arguments;int j = 0;int k, m;va_start(arguments, i);j = va_arg(arguments, int);m = va_arg(arguments, int);va_end(arguments);printf("%d,%d,%d\n",i,j,m);
}/*
2. 固定参数函数
*/
void fixed_args_func(char x, int a, double b, char *c)
{   //打印参数在栈中的地址printf("x = 0x%p\n", &x);printf("a = 0x%p\n", &a);printf("b = 0x%p\n", &b);printf("c = 0x%p\n", &c);
}/*
3. 实现自己的可变参数,实则是按顺序从栈中取出参数的值
*/
void var_args_func(const char * fmt, ...)
{char* ap;ap = (char *)&fmt + sizeof(fmt);int* int_ap = (int *)ap;printf("first:%d\n",*int_ap);int_ap = int_ap + 1;printf("second:%d\n",*int_ap);int_ap = int_ap + 1;// string start indexchar* c_ptr = (char*)int_ap;char* str = (char* )*int_ap;printf("&int_ap = 0x%p\n",int_ap);printf("&c_ptr  = 0x%p\n", c_ptr);printf("&str    = 0x%p\n",str);//栈里面存储的是指向字符串"helloworld的指针",即二级字符指针printf("third1:  %s\n",str);printf("third2:    %s\n", *(char **)int_ap);
}//stdarg.h 中提供的标准可变参数宏
void std_vararg_func(const char *fmt, ...) {va_list ap;va_start(ap, fmt);printf("%d\n", va_arg(ap, int));printf("%f\n", va_arg(ap, double));printf("%s\n", va_arg(ap, char*));va_end(ap);
}int main()
{   fixed_args_func('a',17, 5.40, "hello world");//char* p = "xiongwei";//printf("%d\n",sizeof(p));var_args_func("%d %d %s\n", 4, 5, "helloworld");printf("--------------------------------------\n");std_vararg_func("%d %f %s\n", 4, 5.4, "helloworld");system("pause");return 0;
}

对比一下 std_vararg_func和var_args_func的实现,va_list似乎就是char*, va_start似乎就是((char*)&fmt) + sizeof(fmt),va_arg似乎就是得到下一个参数的首地址。没错,多数平台下stdarg.h中va_list, va_start和var_arg的实现就是类似这样的。一般stdarg.h会包含很多宏,看起来比较复杂。在有的系统中stdarg.h的实现依赖some special functions built into thethe compilation system to handle variable argument lists and stack allocations,多数其他系统的实现与下面很相似:(Visual C++ 6.0的实现较为清晰,因为windows上的应用程序只需要在windows平台间做移植即可,没有必要考虑太多的平台情况)。

first:4second : 5& int_ap = 0x003EF968& c_ptr = 0x003EF968& str = 0x013780D4third1 : helloworldthird2 : helloworld--------------------------------------45.400000helloworld

实现Printf()函数:

#include "stdio.h"
#include "stdlib.h"
void myprintf( char* fmt, ... )         /* 一个简单的类似于printf的实现,//参数必须都是int 类型 */
{char   * pArg = NULL;          /* 等价于原来的va_list */char    c;pArg  = (char *) &fmt;        /* 注意不要写成p = fmt !!因为这里要对//参数取址,而不是取值 */pArg   += sizeof(fmt);         /* 等价于原来的va_start */do{c = *fmt;if ( c != '%' ){putchar( c );   /* 照原样输出字符 */}else     {/*按格式字符输出数据 */switch ( *++fmt ){case 'd':printf( "%d", *( (int *) pArg) );break;case 'x':printf( "%#x", *( (int *) pArg) );break;default:break;}pArg += sizeof(int);    /* 等价于原来的va_arg */}++fmt;}while ( *fmt != '\0' );pArg = NULL;                            /* 等价于va_end */return;
}int main( int argc, char* argv[] )
{int    i   = 1234;int j   = 5678;myprintf( "thefirst test:i=%d", i, j );myprintf( "thesecend test:i=%d; %x;j=%d;", i, 0xabcd, j );system( "pause" );return(0);
}

转载自:https://blog.51cto.com/xwandrew/1974600

C语言可变参数va_list相关推荐

  1. c语言怎样获得函数内参数的值_C语言可变参数函数的实现原理

    在本人的<C语言可变参数函数的实现方法>一文中,介绍了如何建立自己的可变参数函数. 下面继续介绍可变参数函数的实现原理. 在汇编语言程序设计中,详细介绍了子程序的实现思想: (1)子程序只 ...

  2. C语言可变参数函数_初探

    一.什么是可变参数函数 C语言允许定义参数数量可变的函数,这称为可变参数函数(variadic function).这种函数需要固定数量的强制参数,后面是数量可变的可选参数. 其中,强制参数必须至少一 ...

  3. C语言可变参数函数(printf/scanf)

    C 语言允许定义参数数量可变的函数,这称为可变参数函数(variadic function).这种函数需要固定数量的强制参数(mandatory argument),后面是数量可变的可选参数(opti ...

  4. next用法C语言,C语言可变参数的使用

    先来个简单的例子:#include #include void test0(int num,...) { va_list ap; va_start(ap, num); while(num--) { p ...

  5. 理解可变参数va_list、va_start、va_arg、va_end原理及使用方法

     参考: http://www.360doc.com/content/12/0309/10/4025635_192940551.shtml http://www.cnblogs.com/Annie ...

  6. 参数控制c语言代码走向,C语言可变参数完全解读

    本文转自:http://www.cnblogs.com/wangyonghui/archive/2010/07/12/1776068.html 一.是什么 我们学习C语言时最经常使用printf()函 ...

  7. c 语言 可变参数前要加形参,C/C++中可变参数的用法详细解析

    可变参数即表示参数个数可以变化,可多可少,也表示参数的类型也可以变化,可以是int,double还可以是char*,类,结构体等等.可变参数是实现printf(),sprintf()等函数的关键之处, ...

  8. 关于C语言可变参数函数的一些研究和总结

    可变参数函数是指函数参数的个数.类型等是不固定的,需要在用户调用过程中,根据实际传入的参数来确定其类型.个数等信息.例如:可变参数函数printf可谓是在C开发过程中使用最多的标准输出库函数之一,因此 ...

  9. C语言可变参数函数的使用及相关函数介绍

    By qianghaohao(Xqiang) 在C语言中当一个函数参数无法列举出来,或者参数个数  不确定,这时我们将函数声明为可变参数的形式,根据需  要传适当个数的参数.举例如下: int fun ...

  10. 编写可变参数函数 c语言,C语言可变参数函数的编写

    1. 引言 C语言我们接触的第一个库函数是 printf("hello,world!");其参数个数为1个. 然后,我们会接触到诸如: printf("a=%d,b=%s ...

最新文章

  1. Windows系统内存分析工具的介绍
  2. IBM X3100 M4安装centos6.5(RHEL 6.5)说明
  3. 使用Swagger2Markup实现API文档的静态部署(二):Markdown和Confluence
  4. 【django】使用虚拟环境
  5. go数组详解:数组的定义、遍历、使用细节、二维数组的定义及其遍历
  6. Android监听button按钮的click事件
  7. SQL注入:3、无权读取information_schema库和拒绝union、order by语句
  8. centos 怎样显示metric_centos7系列问题
  9. 《深入解析IPv6(第3版)》——11.4 流量转换
  10. Spring 的学习
  11. time.c 的Java实现(从timestamp计算年月日时分秒等数值)
  12. opencv成员函数data,step,at的使用
  13. Fortran入门教程(四)——数据运算
  14. python正则匹配中文
  15. 傲梅分区助手损害大吗_【分区助手技术员v9.00】磁盘分区工具,很好用!
  16. Java音频格式转换,支持amr、aud、slk、silk转成mp3的程序
  17. +new Date是什么意思?
  18. OpenStack腾讯云部署_Nova部署
  19. tecplot——Fluent重叠网格解决方案
  20. 开源的 IM 项目 Sealtalk

热门文章

  1. C语言编程,将26个英文字母大小写输出
  2. LabVIEW控制Arduino采集多路模拟量、数字量(进阶篇—1)
  3. CGAL::2D Arrangements
  4. android支付宝转跳转,APP跳转支付宝指定界面
  5. 【漏洞】——心脏滴血(CVE-2014-0160)
  6. mac虚拟摄像头插件_VCam虚拟摄像头(电脑虚拟摄像头视频软件)V5.4.2 官方最新版...
  7. 浅谈一下Program Files和Program Files(x86)
  8. 关于资金调拨系统的设计方法论
  9. 解决IE7无法设置空白页的办法
  10. Guarded Suspension模式:等待唤醒机制