读书笔记:c语言标准库

· 变长参数(stdarg.h)

  变长参数是c语言的特殊参数形式,例如如下函数声明:

int printf(const char * format,...);

  如此的声明表明,printf函数除了第一个参数类型为const char*之外,其后可以追加任意数量、任意类型的参数。

  在函数实现部分,可以使用stdarg.h里的多个宏来访问各个额外的参数:假设lastarg是变长参数函数的最后一个具名参数(printf里的format),那么在函数内容定义类型为va_list的变量:

va_list ap;

  该变量以后将会依次指向各个可变参数,ap必须用宏va_start初始化一次,其中lastarg必须是函数的最后一个具名的参数。

va_start(ap,lastarg);

  以后,可以使用va_arg宏来获取下一个不定参数(假设已知其类型为type):

type next = va_arg(ap, type);

  在函数结束前,还必须用宏va_end来清理现场。

整理:

  va_list  实际是一个指针,用来指向各个不定参数。由于类型不明,因此这个va_lish以void *或者char *为最佳选择;

  va_start 将va_list定义的指针指向函数的最后一个参数后面的位置,这个位置就是第一个不定参数;

  va_arg   获取当前不定参数的支,并根据当前不定参数的大小将指针指向下一个参数;

  va_end  将指针清0。

  按照以上思路,va系列宏的一个最简单的实现就可以得到如下:

#define va_list char*
#define va_start (ap,arg)  (ap = (va_list)&arg + sizeof(arg))
#define va_arg(ap,t)  (*(t*)((ap+=sizeof(t) - sizeof(t)))
#define va_end(ap)  (ap = (va_list)0)

  

经验:

  在很多时候,我们希望在定义宏的时候也能够像printf函数一样可以使用边长参数,即宏的参数可以是任意个,这个功能可以由编译器的边长参数宏来实现。在GCC编译器下,边长参数宏可以使用“##”宏字符串链接操作实现,比如:

#define printf(arg...) fprintf(stdout,##args)

  而在MSVC下,可以通过__VA_ARGS__这个编译器内置宏,比如:

#define printf(...) fprintf(stdout,__VA_ARGS__)

  

原文地址:https://www.cnblogs.com/Eric-scratch-paper/p/5027703.html