Jan*_*Jan 5 c variadic-functions
我有一个C编程问题:我想编写一个带有变量参数列表的函数,其中每个参数的特定类型都不知道 - 只有它的大小(以字节为单位).这意味着,如果我想获得一个int-Parameter,我(之前的某个地方)定义:将有一个带有sizeof(int)的参数,该参数由回调函数xyz处理.
我的变量参数函数现在应该从其调用中收集所有信息,真正的数据类型特定操作(也可以是用户定义的数据类型)仅通过回调函数进行处理.
在标准的va_arg函数中,不可能说"从我的参数列表中获取X字节的值",所以我想这样做.在这种情况下,我的数据类型是双倍的,但它可以是任何其他数量的字节(甚至是可变的字节).
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
int fn( int anz, ... )
{
char* p;
int i;
int j;
va_list args;
char* val;
char* valp;
int size = sizeof( double );
va_start( args, anz );
val = malloc( size );
for( i = 0; i < anz; i++ )
{
memcpy( val, args, size );
args += size;
printf( "%lf\n", *( (double*)val ) );
}
va_end( args );
}
int main()
{
fn( 1, (double)234.2 );
fn( 3, (double)1234.567, (double)8910.111213, (double)1415.161718 );
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它适用于我,在Linux(gcc)下.但我现在的问题是:这真的很便携吗?或者它会在其他系统和编译器下失败吗?
我的替代方法是取代
memcpy( val, args, size );
args += size;
Run Code Online (Sandbox Code Playgroud)
同
for( j = 0; j < size; j++ )
val[j] = va_arg( args, char );
Run Code Online (Sandbox Code Playgroud)
但后来,我的价值观出错了.
对此有何想法或帮助?
它不便于携带,抱歉。va_list 的格式取决于编译器/平台。
您必须使用 va_arg() 来访问 va_list,并且必须将正确的参数类型传递给 va_list。
但是,我相信如果您将正确大小的类型传递给 va_arg,那可能会起作用。IE。类型通常不相关,只与大小相关。然而,即使这样也不能保证在所有系统上都有效。
我想我建议重新审视你的设计,看看你是否能找到替代设计——是否有更多关于你为什么要尝试这样做的细节可以分享?您可以将 va_list 传递给回调吗?
更新
逐字节方法不起作用的原因可能非常复杂。就 C 标准而言,它不起作用的原因是因为它是不允许的 - 您只能使用 va_arg 来访问传递给函数的相同类型。
但我怀疑你想知道幕后发生了什么:)
第一个原因是,当您将“char”传递给函数时,它实际上会自动提升为 int,因此会作为 int 存储到 va_arg 中。因此,当您读取一个字符时,您正在读取一个“int”的内存,而不是一个“char” - 所以您实际上并不是一次读取一个字节。
另一个原因与对齐有关 - 在某些体系结构上(一个例子是最近的 ARM 处理器),“双精度”必须与 64 位(有时甚至是 128 位)边界对齐。也就是说,对于指针值 p,p % 16(p 模 16,以字节为单位 - 即 128 位)必须等于 0。因此,当这些值打包在 va_arg 上时,编译器可能会确保任何 double 值都有空间(填充)添加,因此它们仅在正确对齐的情况下出现 - 但当您一次读取一个字节的条目时,您不会考虑它。
(也可能还有其他原因 - 我对 va_arg 的内部工作不太熟悉。)