C/C++ 日常学习总结(第十八篇)参数个数可变的函数
2014-09-03 14:11
423 查看
【发生前提】:
这个参数可变的函数一般情况下,我们不怎么会遇到,往往在程序中会把参数个数写死,但是如设置输入输出时会要求参数个数可变,比如:printf(),scanf(),如果想实现自己的printf函数,那么就需要了解其原理。
【函数本质】:
函数参数在内存中是连续存放的。
【基础了解】:
c/c++编译器采用宏的形式支持可变参数函数。这些宏包括va_start、va_arg和va_end等。之所以这么做,是为了增加程序的可移植性。屏蔽不同的硬件平台造成的差异。支持可变参数函数的所有宏都定义在stdarg.h 和 varargs.h中。
使用宏_INTSIZEOF是为了按照整数字节对齐指针,因为c调用协议下面,参数入栈都是整数字节(指针或者值)。
(1.)
(2.)
【实现举例】:
(1.)参数类型是整形int,这种比较容易
(2.)参数类型是字符串类型,注意下面的例子没有使用第一个参数
(3.)在(2)中如何使第一个参数打印出来,为什么打印结果里面没有?那么这就需要去了解上面定义的宏的意义了。
第一句:是调用的
第二句:va_start是_crt_va_start的另一种表现形式
第三句:是_crt_va_start的原型,意思是ap指向的地址是该字符串的首地址+字符串的大小,也就是指向的是第二个字符串的首地址。
修改:
argp = (va_list)_ADDRESSOF(msg);
指向的便是第一个字符串。
这个参数可变的函数一般情况下,我们不怎么会遇到,往往在程序中会把参数个数写死,但是如设置输入输出时会要求参数个数可变,比如:printf(),scanf(),如果想实现自己的printf函数,那么就需要了解其原理。
【函数本质】:
函数参数在内存中是连续存放的。
【基础了解】:
c/c++编译器采用宏的形式支持可变参数函数。这些宏包括va_start、va_arg和va_end等。之所以这么做,是为了增加程序的可移植性。屏蔽不同的硬件平台造成的差异。支持可变参数函数的所有宏都定义在stdarg.h 和 varargs.h中。
使用宏_INTSIZEOF是为了按照整数字节对齐指针,因为c调用协议下面,参数入栈都是整数字节(指针或者值)。
(1.)
#define va_start _crt_va_start #define va_arg _crt_va_arg #define va_end _crt_va_end
(2.)
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) #define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) ) #define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) #define _crt_va_end(ap) ( ap = (va_list)0 )
【实现举例】:
(1.)参数类型是整形int,这种比较容易
int Average1(int first, ...) { int count = 0; int sum = 0; int *p = &first; while (*p != -1) { sum += *(p++); count++; } return( sum ? (sum / count) : 0 ); }
printf( "2, 3, 4之和的平均值 = %d\n", Average1(2, 3, 4, -1)); //最后一个参数-1表示参数结束, 不参与计算 printf( "11, 2, 3, 4之和的平均值 = %d\n\n", Average1(11, 2, 3, 4, -1)); //最后一个参数-1表示参数结束, 不参与计算
(2.)参数类型是字符串类型,注意下面的例子没有使用第一个参数
int demo( char *msg, … ) { va_list argp; /* 定义保存函数参数的结构 */ int argno = 0; /* 纪录参数个数 */ char *para; /* 存放取出的字符串参数 */ // 使用宏va_start, 使argp指向传入的第一个可选参数, // 注意 msg是参数表中最后一个确定的参数,并非参数表中第一个参数 va_start( argp, msg ); while (1) { //取出当前的参数,类型为char * //如果不给出正确的类型,将得到错误的参数 para = va_arg( argp, char *); if ( strcmp( para, “\0″) == 0 ) /* 采用空串指示参数输入结束 */ break; printf(”参数 #%d 是: %s\n”, argno, para); argno++; } va_end( argp ); /* 将argp置为NULL */ return 0; } //输出结果 参数 #0 是: This 参数 #1 是: is 参数 #2 是: a 参数 #3 是: demo!
void main( void ) { demo(”DEMO”, “This”, “is”, “a”, “demo!”, “\0″); }
(3.)在(2)中如何使第一个参数打印出来,为什么打印结果里面没有?那么这就需要去了解上面定义的宏的意义了。
va_start( argp, msg ); #define va_start _crt_va_start #define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
第一句:是调用的
第二句:va_start是_crt_va_start的另一种表现形式
第三句:是_crt_va_start的原型,意思是ap指向的地址是该字符串的首地址+字符串的大小,也就是指向的是第二个字符串的首地址。
修改:
argp = (va_list)_ADDRESSOF(msg);
指向的便是第一个字符串。
相关文章推荐
- C++学习之可变参数的函数与模板
- C++学习之可变参数的函数与模板
- C/C++日常学习总结(第十一篇)函数指针
- 今天学习了关于C++ 中可变参数个数函数的使用!
- 【C++学习与应用总结】1: 两种变长参数函数比较
- C/C++ 日常学习总结(第二十篇)实现自己的printf函数
- C++学习总结(十一)——类的静态函数,成员函数的默认参数,类中包含引用和常量
- C++学习之可变参数的函数与模板
- C/C++日常学习总结(第六篇)多基派生引起的虚函数访问二义性问题&重载,覆盖,隐藏的区别
- c++技巧之可变参数函数
- C++与C#对比学习:函数(一)C#参数传递存在的问题
- 黑马程序员—反射调用main方法的问题总结(涉及可变参数)(反射参数是一个数组的函数要小心)
- C++:可变参数函数
- 函数参数传递 c++学习
- Java学习总结(一)—— >Java环境变量的配置,DOS窗口的带包编译,Jdk1.5的两个新特性(可变参数和增强的for循环)
- 可变参数函数总结
- C++学习总结_成员函数的声明和实现需要注意问题
- 学习C++Primer Plus 函数探幽总结
- [C/C++]函数参数的入栈顺序与可变参数的实现
- C/C++里面使用的可变参数函数