在C程序设计语言中,使用printf函数进行标准输出。
int printf ( const char * format, ... );
printf函数申明中"..."代表可变参数。
printf ("floats: %4.2f %+.0e %E \n", 3.1416, 3.1416, 3.1416); printf ("Width trick: %*d \n", 5, 10);
那么,如何实现可变参数?
近日,在读Linux0.12源代码的过程中,我看到了一个实现。下面,我给出一个demo程序。
#include <iostream> using namespace std; typedef char *va_list; #define __va_rounded_size(TYPE) (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int)) #define va_start(AP, LASTARG) (AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG))) #define va_end(AP) #define va_arg(AP, TYPE) (AP += __va_rounded_size (TYPE), *((TYPE *) (AP - __va_rounded_size (TYPE)))) void print_args(int args, ...) { va_list ap; //在访问任何未命名的参数之前,必须用va_start宏初始化ap一次 va_start(ap,args); printf("%d\n",args); printf("%d\n",va_arg(ap,int)); printf("%s",va_arg(ap,char *)); // va_end(ap); } int main(void) { int arg = 2; int args1 = 1; char *args2 = "abcdefg"; print_args(2,args1,args2); return 0; }
不妨在print_args程序中设置一个断点。
首先,查看一下args参数的内存地址:
+ &args 0x0028f71c int *
现在,我们查看0x0028f71c处的内存:
0x0028F71C 02 00 00 00 .... 0x0028F720 01 00 00 00 .... 0x0028F724 08 58 cd 00 .X?.
显然, 0x0028f71c处的4个字节为0x00000002,即main函数中的arg参数;
0x0028f720处的4个字节为0x00000001,即main函数中的args1参数;
而0x0028f724处的4个字节内容为0x00cd5808,这是一个内存地址;
0x00CD5808 61 62 63 64 abcd 0x00CD580C 65 66 67 00 efg.
继续查看0x00cd5808处的内存,可以看出正是"abcdefg\0"。
有了上面的基础,我们应当可以理解va_start, va_end和va_arg宏了。实际上,就是对地址的操作,以及强制类型转换。printf函数也是利用上面3个宏实现可变参数功能的。
时间: 2024-10-18 22:27:38