lab1的头文件: inc/stdarg.h, 其全部内容如下:
#ifndef JOS_INC_STDARG_H
#define JOS_INC_STDARG_H
typedef char *va_list;
#define __va_size(type) \
(((sizeof(type) + sizeof(long) - 1) / sizeof(long)) * sizeof(long))
#define va_start(ap, last) \
((ap) = (va_list)&(last) + __va_size(last))
#define va_arg(ap, type) \
(*(type *)((ap) += __va_size(type), (ap) - __va_size(type)))
#define va_end(ap) ((void)0)
#endif /* !JOS_INC_STDARG_H */
此文件用于函数调用时候对堆栈的处理。
宏 __va_size: 计算变量type的size。 由于在32-bit的机器上,堆栈的增减始终是以32bit为单位,所以必须将type处理成32-bit对齐。 引用项目中的一句原话:In 32-bit mode, the stack can only hold 32-bit values,
and esp is always divisible by four. 该定义中使用long类型,说明所用的是32-bit机器。
宏 va_start(ap, last): 用于移动char*指针, 指向栈里last所在位置的下一个位置(即靠近栈底的位置)。 以函数cprintf()为例(kern/printf.c):
int
cprintf(const char *fmt, ...)
{
va_list ap;
int cnt;
va_start(ap, fmt);
cnt = vcprintf(fmt, ap);
va_end(ap);
return cnt;
}
则va_start(ap, fmt);之后,ap将指向fmt之后的参数。 假如有如下函数调用: cprintf("%s%d\n", "hello", 32); 则ap指向栈里保存字符串“hello“的位置。
之所以va_start将会向参数后面移动,从而指向栈的下一个位置,是因为函数调用时,入栈顺序是和参数位置相反的。因此,cprintf("%s%d\n", "hello", 32)的入栈位置为32, “hello“, ”%s%d\n", 而ap的值增加的结果就是向栈底移动,即va_start(ap, "%s%d\n")使ap从”%s%d\n"指向“hello“, 而va_start(ap, "hello")将使得ap从”hello“指向32。
宏 va_arg(ap, type): 返回栈里ap所指向的位置的值,并且将ap指向栈的下一个位置。假如有如下语句: cprintf("%s%d\n", "hello", 32); 其实现为: va_start(ap, "%s%d\n"), c=va_arg(ap, (char *)), 则此时ap指向32, c的值指向“hello“的指针。
阅读(2025) | 评论(0) | 转发(1) |