这个参数咋传,跟你用得编译器、操作系统,目标体系结构都有关 ... ,可以去看一下Calling Convetion简单了解一下。
对 gcc Linux x86-64 来说,开始的几个参数根本不在栈里,而是用的寄存器。
把你的函数拼了个程序,放到godbolt上看了一下:
void func(const char *fmt, ...)
{
printf("%p", &fmt);
}
int main(int argc, const char **argv) {
func("test", 1, 2, 3, 4, 5, 6, 7);
}
func 的调用是这样:
push 7
push 6
mov r9d, 5
mov r8d, 4
mov ecx, 3
mov edx, 2
mov esi, 1
mov edi, OFFSET FLAT:.LC1
mov eax, 0
call func
add rsp, 16
mov eax, 0
可以看出除了 6 跟 7 ,其他所有参数都在寄存器里。
进入 func 之后,这些参数又被从寄存器放回了内存(为了实现 va_list 等等 ...):
push rbp
mov rbp, rsp
sub rsp, 192
mov QWORD PTR [rbp-184], rdi
mov QWORD PTR [rbp-168], rsi
mov QWORD PTR [rbp-160], rdx
mov QWORD PTR [rbp-152], rcx
mov QWORD PTR [rbp-144], r8
mov QWORD PTR [rbp-136], r9
然而第一个参数跟后续的并不连续,并且参数 5 (后放进内存的)跟 参数 6 (直接压栈)也并不连续。
最后,其他的编译器/操作系统/体系结构的组合,可能完全不是这么搞的。比如 x86(32位) ,所有参数都会被压倒栈里。