本文是基于韦东山视频的学习笔记
pintf格式
参考printf函数
int printf(const char *format,…)
- “*format”为固定参数
- “…”为可变参数
可变参数
固定参数便是传入的字符串,而重点在于怎么传递可变参数。
我们知道,在x86平台,函数调用时参数传递是使用堆栈来实现的,上图。
比如如下代码
struct Stu {
char* name;
int num1;
char c;
int num2
}
void MyPrintf(char* format, ...)
{
...
}
int main()
{
...
MyPrintf("abcd", 123, Stu, 'c', 10.12);
}
其中,main
函数中的format
是定参,后面的123
是可变参数1,Stu
是可变参数2,c
是可变参数3,10.12
是可变参数4,在堆栈中如下分布。
可变参数的取值
参数指针从format
开始传入,如果想指向可变参数1,就指针+4即可,如此类推,有以下代码辅助实现:
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //这一句实现取参、指针移向下一个变参
#define va_end(ap) ( ap = (va_list)0 )
字节对齐
值得注意的是,在这个gcc 编译都是4字节对齐,包括结构体的字符类型。如果想取消对齐,用__attribute__ ((packed))
修饰即可,如:
struct person{
char *name;
int age;
char score;
int id;
}__attribute__ ((packed));
还可以指定对齐,如下
struct person{
char *name;
int age;
char score;
int id;
}__attribute((aligned (4)));
/usr/include/features.h:367:25: fatal error: sys/cdefs.h: No such file or directory
解决Ubuntu编译error:fatal error: sys/cdefs.h: No such file or directory–InWho
Some packages could not be authenticated
E: Some packages could not be authenticated–Simon_CB_Zhao
vc6.0 中的 stdarg.h
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) //4字节对齐
//#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_arg(ap,t) ( *(t *)( ap=ap + _INTSIZEOF(t), ap- _INTSIZEOF(t)) ) //移动指针 & 取值
#define va_end(ap) ( ap = (va_list)0 ) //ap = (char *)(0)