波音网站开发,官方网站下载打印机驱动,河南省新闻最新消息,营销型网站建设 pptC语言可变参数
使用printf等函数的时候函数原型是printf(const char* fmt, ...), 这一类参数的个数不限的函数是可变参数
使用
使用一个头文件stdarg.h, 主要使用以下的宏
typedef char * va_list;// 把 n 圆整到 sizeof(int) 的倍数
#define _INTSIZEOF(n) ( (sizeo…C语言可变参数
使用printf等函数的时候函数原型是printf(const char* fmt, ...), 这一类参数的个数不限的函数是可变参数
使用
使用一个头文件stdarg.h, 主要使用以下的宏
typedef char * va_list;// 把 n 圆整到 sizeof(int) 的倍数
#define _INTSIZEOF(n) ( (sizeof(n)sizeof(int)-1) ~(sizeof(int)-1) )// 初始化 ap 指针使其指向第一个可变参数。v 是变参列表的前一个参数
#define va_start(ap,v) ( ap (va_list)v _INTSIZEOF(v) )// 使用type进行一个类型的转换,
#define va_arg(ap, type) ( *(type *)((ap _INTSIZEOF(type)) - _INTSIZEOF(type)) )// /将指针 ap 置为无效结束变参的获取
#define va_end(ap) ( ap (va_list)0 )C语言可变参数详解_c语音 可变参数-CSDN博客 在函数定义中创建一个 va_list 类型变量该类型是在 stdarg.h 头文件中定义的。 使用 int 参数和 va_start() 宏来初始化 va_list 变量为一个参数列表。宏 va_start() 是在 stdarg.h 头文件中定义的。 使用 va_arg() 宏和 va_list 变量来访问参数列表中的每个项。 使用宏 va_end() 来清理赋予 va_list 变量的内存。 va_start(ap, last_arg)初始化可变参数列表。ap 是一个 va_list 类型的变量last_arg 是最后一个固定参数的名称也就是可变参数列表之前的参数。该宏将 ap 指向可变参数列表中的第一个参数。 va_arg(ap, type)获取可变参数列表中的下一个参数。ap 是一个 va_list 类型的变量type 是下一个参数的类型。该宏返回类型为 type 的值并将 ap 指向下一个参数。 va_end(ap)结束可变参数列表的访问。ap 是一个 va_list 类型的变量。该宏将 ap 置为 NULL。 原理 实际是从栈里面依次获取下一个字符串的指针地址 这里分析这两个函数的汇编代码 可以看出多出来的参数是依次被压入栈中进行传递的, 所以使用的时候可以使用最后一个参数的地址以及大小推导出来下一个参数的位置, 这里之后的参数实际是按照字符串指针的格式存储的 这里使用的栈是向下增长的, 但是压入的顺序是从右向左 如果使用fun(a, b)实际的栈里面是 再来看前面库函数
typedef char * va_list;// 把 n 调整到 sizeof(int) 的倍数(这一个是用来计数对齐的, 栈的存储是对齐的)
#define _INTSIZEOF(n) ( (sizeof(n)sizeof(int)-1) ~(sizeof(int)-1) )// 可以通过(va_list)v获取已知最后一个参数的地址加上它的大小就是第一个参数的位置
#define va_start(ap,v) ( ap (va_list)v _INTSIZEOF(v) )// 使用type进行一个类型的转换, 转换的是现在的参数的地址, ap以后会指向下一个的位置
#define va_arg(ap, type) ( *(type *)((ap _INTSIZEOF(type)) - _INTSIZEOF(type)) )// /将指针 ap 置为无效结束变参的获取
#define va_end(ap) ( ap (va_list)0 )实现一个简单的sprintf(只处理%s)
void kernel_vsprintf(char * buf, const char *fmt, ...){va_list args;//记录第一个可变参数的位置va_start(args, fmt);//一个状态机enum {NORMAL, READ_FMT} state NORMAL;char * curr buf;char ch;while((ch *fmt)){switch(state) {case NORMAL:if(ch %){//需要处理这一个格式字符state READ_FMT;}else{//普通字符直接复制*curr ch;}break;case READ_FMT:if(ch s){//需要填入一个字符串//获取这一个字符串的地址const char * str va_arg(args, char *);int len strlen(str);while(len--){*curr *str;}}state NORMAL;break;}}
}