【发布时间】:2021-07-25 01:22:48
【问题描述】:
我阅读了可变参数函数以及数据类型和宏的工作原理,我以为我理解了它的工作原理,但我发现有些不同,这是我一直在尝试的,我对不同宏和数据的理解输入工作:
typedef char * va_list;
#define va_start( ap, v ) ap = (char *)&v + sizeof( v )
#define va_arg( ap, t ) ( (t *) ( ap += sizeof( t ) )[-1]
#define va_end( ap ) ap = NULL
所以这只是一个指针,它一次移动 1 个字节并移动 t 数据类型使用的字节数,所以我尝试在不使用此宏或 <stdarg.h> 的情况下复制行为,只是为了更好地理解它是如何工作的,使用标头的函数的代码是这样的:
int _print_ints(int n, ...)
{
va_list listArgs;
va_start( listArgs, n );
for(int i = 0; i < n; i++)
{
printf("%3d ", va_arg( listArgs, int ) );
}
va_end( listArgs );
}
它按预期工作,我制作的代码是这样的:
int print_ints(int n, ...)
{
char *arg = (char *)&n;
for(int i = 0; i < n; i++)
{
int val = *( (int *) (arg += sizeof( int ) * 2 ) );
printf("%3d ", val);
}
arg = NULL;
}
这个也可以按预期工作,但是,你看我必须移动两倍于我最初必须移动的假定大小,而不是移动每个变量的 4 bytes(我的系统中的 int 大小),我有移动 8 bytes 这是一个长长的大小,代码中的常量变量是 int 所以我真的不明白为什么在堆栈中为了从一个变量移动到另一个我必须移动两倍的大小,这里是满的代码:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
int _print_ints(int n, ...)
{
va_list listArgs;
va_start( listArgs, n );
for(int i = 0; i < n; i++)
{
printf("%3d ", va_arg( listArgs, int ) );
}
va_end( listArgs );
}
int print_ints(int n, ...)
{
char *arg = (char *)&n;
for(int i = 0; i < n; i++)
{
int val = *( (int *) (arg += sizeof( int ) * 2 ) );
printf("%3d ", val);
}
arg = NULL;
}
int main( void )
{
_print_ints(5, 1, 2, 3, 4, 5);
printf("\n");
print_ints(5, 6, 7, 8, 9, 10);
return EXIT_SUCCESS;
}
它输出:
1 2 3 4 5
6 7 8 9 10
总结一下,为什么我必须移动sizeof( int ) * 2 而不是sizeof( int )?
可能是我得到信息的书已经过时了
【问题讨论】:
-
当今流行的架构——特别是标准的 x86 和 x86_64 ABI——不在堆栈上传递所有参数。某些参数是在寄存器中传递的。因此,像这样的简单、传统、基于指针的
va_arg实现不起作用并且不再使用。