C、C++格式化字符串
引言在C和C++开发中,我们经常会用到printf来进行字符串的格式化,例如 你可以在这里看到更好的排版 正文可变参数首先来一个可变参数使用示例, /** 下面是 <stdarg.h> 里面重要的几个宏定义如下: typedef char* va_list; void va_start ( va_list ap,prev_param ); // ANSI version type va_arg ( va_list ap,type ); void va_end ( va_list ap ); va_list 是一个字符指针,可以理解为指向当前参数的一个指针,取参必须通过这个指针进行。 <Step 1> 在调用参数表之前,定义一个 va_list 类型的变量,(假设va_list 类型变量被定义为ap); <Step 2> 然后应该对ap 进行初始化,让它指向可变参数表里面的第一个参数,这是通过 va_start 来实现的,第一个参数是 ap 本身,第二个参数是在变参表前面紧挨着的一个变量,即“...”之前的那个参数; <Step 3> 然后是获取参数,调用va_arg,它的第一个参数是ap,第二个参数是要获取的参数的指定类型,然后返回这个指定类型的值,并且把 ap 的位置指向变参表的下一个变量位置; <Step 4> 获取所有的参数之后,我们有必要将这个 ap 指针关掉,以免发生危险,方法是调用 va_end,他是输入的参数 ap 置为 NULL,应该养成获取完参数表之后关闭指针的习惯。说白了,就是让我们的程序具有健壮性。通常va_start和va_end是成对出现。 */ //-1表示可变参数结束 void receiveVariadic(int a,...) { va_list list; va_start(list,a); int arg = a; while (arg != -1) { arg = va_arg(list,int); printf("%d ",arg); } printf("n"); va_end(list); } //test void testVari() { printf("------%s------n",__FUNCTION__); //-1表示可变参数结束 receiveVariadic(1,2,3,4,5,6,-1); } 运行结果 ------testVari------ 2 3 4 5 6 -1 格式化字符串好了,我们已经介绍了怎样实现一个接收可变参数的C函数,接下来介绍根据接收的可变参数来格式化字符串。这里介绍两种方式,第一种是利用宏定义,第二种通过函数的方式来实现。 通过宏定义的方式en…让咱们先来看看第一个版本的宏,这个宏定义对于不熟悉宏的人来说可能看着有点费劲,不过不要怕,稍后会做解释,代码如下: #define myFormatStringByMacro_WithoutReturn(format,...) do { int size = snprintf(NULL,format,##__VA_ARGS__); size++; char *buf = (char *)malloc(size); snprintf(buf,size,##__VA_ARGS__); printf("%s",buf); free(buf); } while(0) 宏基础知识首先需要介绍宏用到的知识: 你一定会觉得困惑,为什么要写 #define testMarco(a,b) int _a = a + 1; int _b = b + 1; printf("n%d",_a + _b); void test() { if (1 > 0) testMarco(1,2); } 上面的代码连编译都不会通过,会报错如下: 如果手动展开这个宏的话,会变成这个样子,问题就显而易见了。但是如果 void test() { if (1 > 0) int _a = 1 + 1; int _b = 2 + 1; printf("n%d",_a + _b);; } 加上 #define testMarco(a,b) do { int _a = a + 1; int _b = b + 1; printf("n%d",_a + _b); } while(0) void test() { if (1 > 0) testMarco(1,2); } 预处理之后代码如下: //展开后的代码 void test() { if (1 > 0) do { int _a = 1 + 1; int _b = 2 + 1; printf("n%d",_a + _b); } while(0); } 好了,宏的基础知识就介绍这么多了,接下来进入正题。 代码解析为了方便阅读,原谅我在这里再贴一遍宏定义的代码: #define myFormatStringByMacro_WithoutReturn(format,buf); free(buf); } while(0) 首先,介绍一下 /** @param __str 接收格式化结果的指针 @param __size 接收的size @param __format 格式化的字符串 @param ... 可变参数 @return 返回格式化后实际上写入的大小a,a <= __size */ int snprintf(char * __restrict __str,size_t __size,const char * __restrict __format,...) __printflike(3,4); 为了方便理解,使用方式是这个样子的: void testSnprintf() { printf("------%s------n",__FUNCTION__); char des[50]; int size = snprintf(des,50,"less length %d",50); printf("size:%dn",size); } 运行结果: ------testSnprintf------ size:14
|