void fun2(char *format, ...){
   va_list arg_list;
   va_start(arg_list, format);
   vprintf(format, arg_list);
   va_end(arg_list);
}

void fun1(char *format, ...){
   fun2(format);
}

int main(){
   fun1("test: %d", 100);
}

输出:

测试:100

https://onlinegdb.com/OfdDeSJg_

上述示例是否有错误或不推荐的地方?

我猜当进行fun2(format);调用时,只传递指向第一个参数(format)的指针,对吗?

fun2中的vprintf访问整数vprintf时,这个整数在哪里?在为fun1保留的堆栈中,在为fun2保留的堆栈中,在为vprintf保留的堆栈中,还是在其他地方?

如果像我想象的那样,只有指向第一个参数的指针被传递到fun2,这是否意味着当fun2调用的函数和宏访问整数fun2时,它们正在访问为fun1保留的堆栈?

推荐答案

它们没有被转发.除非你运气好,否则这个代码不起作用.

如果幸运的话,这可能是因为优化器看到format保持在相同的参数位置(寄存器或堆栈),所以fun1实际上没有任何"真实"代码(它不会移动任何参数),所以它将fun1更改为直接跳到fun2的跳转指令(也称为尾部调用优化).然后,由于fun1没有处理任何参数,也没有创建堆栈帧,因此它们仍然处于调用void (char*, ...)函数的正确位置,fun1在其中拾取它们.

i、 e.汇编代码可能是这样的:

// Pretend calling convention: format is in ecx, and varargs on the stack

fun2:
    // actual code would go here
    ret

fun1:
    // jmp instruction doesn't affect the stack, nor ecx
    // so fun2 receives exactly the same inputs as if main
    // had directly called fun2
    jmp fun2

main:
    mov ecx, "test: %d"
    push 100
    call fun1
    ret

你不能依赖它.如果您想可靠地转发varargs,您可以将函数更改为使用va\u列表参数(如vprintf),或者编写自己的汇编代码.

C++相关问答推荐

根据工具链文件中的定义替换单个函数定义

ARM上的Modulo Sim Aarch 64(NEON)

漏洞仅出现在FreeBSD上,但在Windows、Linux和MacOS上运行得非常好

为什么静态说明符为内联函数生成外部定义?

Apple Libm的罪恶功能

ISO_C_BINDING,从Fortran调用C

exit(EXIT_FAILURE):Tcl C API类似功能

在#include中使用C宏变量

在函数中使用复合文字来初始化C语言中的变量

ARM64 ASIMD固有的加载uint8_t* 到uint16x8(x3)?

为什么即使在强制转换时,此代码也会溢出?

正确的TCP/IP数据包 struct

防止C++中递归函数使用堆栈内存

如何计算打印二叉搜索树时每行所需的空间?

在for循环中指向数组开头之前

在vfork()之后,链接器如何在不 destruct 父内存的情况下解析execve()?

在C程序中使用Beaglebone Black UART的问题

在C中使用无符号整数模拟有符号整数

当另一个指向 const 的指针观察到数据时,通过指针更改数据是否安全?

将数组返回到链表