点击(此处)折叠或打开
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <stdarg.h> int f(int x, int y, int z) { return x + y + z; } int sum(int size, ...) { va_list vp; int s = 0; int i = 0; va_start(vp, size); for (i = 0; i < size; ++ i) { s += va_arg(vp, int); } va_end(vp); printf("%d,%d\n", size, s); } int main() { int a = 1; int b = 2; int c = 3; printf("%d\n", f(a, b , c)); sum(5, 20, 30, 40, 50, 20); return 0; } 有关va_list的用法还很多,在报文解析相关的代码中存在很多处理,该例子是获取相同类型的数据,在格式化处理中可能存在各种各种的格式,只需要根据不同的格式分别获取参数就能完成复杂格式的处理。这部分可以参看redis-cli对cli的处理逻辑,如下所示:点击(此处)折叠或打开
void *redisCommand(redisContext *c, const char *format, ...) { va_list ap; void *reply = NULL; va_start(ap,format); //已format作为可变参数的相对起始地址 reply = redisvCommand(c,format,ap); //对ap进行处理 va_end(ap); return reply; } 接下来查看ap相关的操作逻辑:点击(此处)折叠或打开
int redisvFormatCommand(char **target, const char *format, va_list ap) { const char *c = format; char *cmd = NULL; /* final command */ int pos; /* position in final command */ sds curarg, newarg; /* current argument */ int touched = 0; /* was the current argument touched? */ char **curargv = NULL, **newargv = NULL; int argc = 0; int totlen = 0; int j; /* Abort if there is not target to set */ if (target == NULL) return -1; /* Build the command string accordingly to protocol */ curarg = sdsempty(); if (curarg == NULL) return -1; while(*c != '\0') { if (*c != '%' || c[1] == '\0') { if (*c == ' ') { if (touched) { newargv = realloc(curargv,sizeof(char*)*(argc+1)); if (newargv == NULL) goto err; curargv = newargv; curargv[argc++] = curarg; totlen += bulklen(sdslen(curarg)); /* curarg is put in argv so it can be overwritten. */ curarg = sdsempty(); if (curarg == NULL) goto err; touched = 0; } } else { newarg = sdscatlen(curarg,c,1); if (newarg == NULL) goto err; curarg = newarg; touched = 1; } } else { char *arg; size_t size; /* Set newarg so it can be checked even if it is not touched. */ newarg = curarg; switch(c[1]) { case 's': //字符串的处理 arg = va_arg(ap,char*); size = strlen(arg); if (size > 0) newarg = sdscatlen(curarg,arg,size); break; case 'b': arg = va_arg(ap,char*); //先获取字符串地址 size = va_arg(ap,size_t); //获取字符串的长度 if (size > 0) newarg = sdscatlen(curarg,arg,size); break; case '%': newarg = sdscat(curarg,"%"); break; default: /* Try to detect printf format */ { static const char intfmts[] = "diouxX"; char _format[16]; const char *_p = c+1; size_t _l = 0; va_list _cpy; /* Flags */ if (*_p != '\0' && *_p == '#') _p++; if (*_p != '\0' && *_p == '0') _p++; if (*_p != '\0' && *_p == '-') _p++; if (*_p != '\0' && *_p == ' ') _p++; if (*_p != '\0' && *_p == '+') _p++; /* Field width */ while (*_p != '\0' && isdigit(*_p)) _p++; /* Precision */ if (*_p == '.') { _p++; while (*_p != '\0' && isdigit(*_p)) _p++; } /* Copy va_list before consuming with va_arg */ va_copy(_cpy,ap); /* Integer conversion (without modifiers) */ if (strchr(intfmts,*_p) != NULL) { va_arg(ap,int); //获取参数 goto fmt_valid; } /* Double conversion (without modifiers) */ if (strchr("eEfFgGaA",*_p) != NULL) { va_arg(ap,double); //获取浮点数 goto fmt_valid; } /* Size: char */ if (_p[0] == 'h' && _p[1] == 'h') { _p += 2; if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { va_arg(ap,int); /* char gets promoted to int */ goto fmt_valid; } goto fmt_invalid; } /* Size: short */ if (_p[0] == 'h') { _p += 1; if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { va_arg(ap,int); /* short gets promoted to int */ goto fmt_valid; } goto fmt_invalid; } /* Size: long long */ if (_p[0] == 'l' && _p[1] == 'l') { _p += 2; if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { va_arg(ap,long long); goto fmt_valid; } goto fmt_invalid; } /* Size: long */ if (_p[0] == 'l') { _p += 1; if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { va_arg(ap,long); goto fmt_valid; } goto fmt_invalid; } fmt_invalid: va_end(_cpy); goto err; fmt_valid: _l = (_p+1)-c; if (_l < sizeof(_format)-2) { memcpy(_format,c,_l); _format[_l] = '\0'; newarg = sdscatvprintf(curarg,_format,_cpy); /* Update current position (note: outer blocks * increment c twice so compensate here) */ c = _p-1; } va_end(_cpy); break; } } if (newarg == NULL) goto err; curarg = newarg; touched = 1; c++; } c++; } /* Add the last argument if needed */ if (touched) { newargv = realloc(curargv,sizeof(char*)*(argc+1)); if (newargv == NULL) goto err; curargv = newargv; curargv[argc++] = curarg; totlen += bulklen(sdslen(curarg)); } else { sdsfree(curarg); } /* Clear curarg because it was put in curargv or was free'd. */ curarg = NULL; /* Add bytes needed to hold multi bulk count */ totlen += 1+intlen(argc)+2; /* Build the command at protocol level */ cmd = malloc(totlen+1); if (cmd == NULL) goto err; pos = sprintf(cmd,"*%d\r\n",argc); for (j = 0; j < argc; j++) { pos += sprintf(cmd+pos,"$%zu\r\n",sdslen(curargv[j])); memcpy(cmd+pos,curargv[j],sdslen(curargv[j])); pos += sdslen(curargv[j]); sdsfree(curargv[j]); cmd[pos++] = '\r'; cmd[pos++] = '\n'; } assert(pos == totlen); cmd[pos] = '\0'; free(curargv); *target = cmd; return totlen; err: while(argc--) sdsfree(curargv[argc]); free(curargv); if (curarg != NULL) sdsfree(curarg); /* No need to check cmd since it is the last statement that can fail, * but do it anyway to be as defensive as possible. */ if (cmd != NULL) free(cmd); return -1; } 从上述的代码中实际上是对va_list进行反复的操作获取具体的内容。通过va_list就能相对简单的解决格式化操作。 <script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script> 阅读(405) | 评论(1) | 转发(0) | 0上一篇:标准I/O缺陷
下一篇:C小程序 - setbuf和setvbuf
相关热门文章 test123编写安全代码——小心有符号数...使用openssl api进行加密解密...一段自己打印自己的c程序...彻底搞定C语言指针详解-完整版... 给主人留下些什么吧!~~183450931672016-08-07 09:52:13
可变参数求和的写法:#include<stdio.h>int sum(int n,...){ int sum1 = 0; int i = 0; for (i = 0;i < n;i++) { sum1 += *(int *)(&n+i+1); } return sum1;}int main(){ printf(\"%d\\n\",sum(3,1,2,3)); return 0;}
回复 | 举报 评论热议