今天我们来探究一下c语言之可变长参数的秘密。我相信看了这篇文章后,c语言的可变长参数就不再有什么秘密。
一、函数参数的入栈
1.1 函数的参数如何传递
在c语言的函数调用中,有些函数需要参数的传入。编译器是如何实现的呢?首先在函数的调用时,会为即将调用的函数准备一个栈,然后将输入参数按照实参的顺序从右到左依次压入栈中了。
例如:
void func(arg0, arg1, arg2, arg3, arg3, arg4)
程序会依次将arg4, arg3, arg2, arg1, arg0压入栈中,程序运行栈如下:
---------栈底------
[arg4]
[arg3]
[arg2]
[arg1]
[arg0]
---------栈顶------
1.2 特殊符号 ...
编译器在c源码的编译中遇到了 ... 这种特殊符号时,编译器会检查在... 符号前面是否至少 有一个常规参数(普通形参)。如果没有,源码在编译中就会报错。除此之外,编译器也会生成进行输入参数压栈常规操作。
正确实例:
int func1(int a, ...)
int func2(const char* f, ...)
int func3(int a, int* b, const char* f, ...)
错误实例:
int func5(...)
int func5(int a, const char* f, ..., int b)
1.3 定位参数
用来定位可变长参数列表开始的地址。例如func1 中,在变量a中偏移4个字节就是可变长参数列表开始的地址。 func3中b就是可变长度定位参数。
二、如何取出函数参数列表
2.1 宏解读
typedef char * va_list;
#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )
&

本文揭示了C语言中可变长参数的秘密,包括函数参数的入栈过程、...符号的使用规则、定位参数的概念,以及如何通过宏来取出和使用函数参数列表。通过对va_start、va_arg和va_end等宏的解读,详细阐述了实现printf等功能的底层原理。
最低0.47元/天 解锁文章
2987

被折叠的 条评论
为什么被折叠?



