dri*_*ker 12 c variadic-functions
我正在尝试使用带有泛型类型的C stdarg.h lib.int类型,是我的泛型类型>要理解它,请继续阅读.所以,我的问题是:
我有一个函数接受可变数量的参数.喜欢
void function (int paramN, ...);Run Code Online (Sandbox Code Playgroud)
在我的程序中,没有办法知道,哪个是变量参数的类型,它可以是char,数组,int,short,函数点等...就像
function (paramN, "Hey, I'm a string", 1, function_pint, array, -1); // -1 is a sentinel.Run Code Online (Sandbox Code Playgroud)
所以,我认为,一个int,是32位,在x86(32位)系统中,这将保存所有内存地址.所以,如果我用int得到所有参数,那就不会有问题了,例如,"嘿,我是一个字符串"这个字符串的地址,通常适合32位变量,所以,我只需要制作演员.
我是正确的?
我可以做吗?
注意:我不想让我的函数像printf(这个解决方案,在这种情况下不适合好吗?)
谢谢你的回答.
抱歉我的英语不好.
jld*_*ont 14
对每个参数使用void*(或类型化结构)并使用带有"type"参数(整数)的结构.用于包含实际值的指针/联合.
换句话说,每个参数都使用指向类型化结构的指针传递.此类型结构的每个实例都包含一个值.此"值"的类型包含在此类型结构中.
更好的例子:
typedef struct {
int type;
union {
int int_value;
double double_value;
...
};
} Param;
Run Code Online (Sandbox Code Playgroud)
void function(Param *p1, Param *p2, ...)
我遇到的这种技巧的最新例子是DBus.
kri*_*iss 11
你无法按照描述的方式去做.
C调用约定是让调用者将参数放在堆栈上,但它不会在类型上放置任何信息,因此被调用者必须有办法找到它(至少是变量的大小).
对于每种类型的原型的函数都没有问题.
对于具有可变数字或参数(可变参数)的函数,它更棘手,您必须为每个参数调用va_arg来读取每个变量,并且必须为va_arg提供类型.如果你提供的类型不是真正的类型,编译器不会抱怨(它不能是运行时信息),但任何事情都可能发生(通常是坏事).
因此你必须传递这种类型.
在某些情况下,您可以预测类型(例如:一个计数器后跟一些整数,依此类推),但通常您将其传递给参数编码.你可以传递它像printf那样的格式字符串编码,jldupont描述的联合技巧也很常见.
但无论如何你必须通过它.
你真的不能依赖底层数据二进制表示,甚至数据大小.即使程序在编写时似乎有效,它也没有兼容性,并且可以在系统,编译器或更改编译选项的任何更改时中断.
让我们来看一个例子,你传递类型后跟参数(因此既不是联合技巧也不是像printf这样的格式字符串).它的作用是将所有传递的值转换为double并添加它们,不是真的有用不是它:
#include <stdio.h>
#include <stdarg.h>
enum mytypes {LONG, INT, FLOAT, DOUBLE };
double myfunc(int count, ...){
long tmp_l;
int tmp_i;
double tmp_d;
double res = 0;
int i;
va_list ap;
va_start(ap, count);
for(i=0 ; i < count; i++){
int type = va_arg(ap, enum mytypes);
switch (type){
case LONG:
tmp_l = va_arg(ap, long);
res += tmp_l;
break;
case INT:
tmp_i = va_arg(ap, int);
res += tmp_i;
break;
case FLOAT:
/* float is automatically promoted to double when passed to va_arg */
case DOUBLE:
tmp_d = va_arg(ap, double);
res += tmp_d;
break;
default: /* unknown type */
break;
}
}
va_end(ap);
return res;
}
int main(){
double res;
res = myfunc(5,
LONG, (long)1,
INT, (int)10,
DOUBLE, (double)2.5,
DOUBLE, (double)0.1,
FLOAT, (float)0.3);
printf("res = %f\n", res);
}
Run Code Online (Sandbox Code Playgroud)
此示例使用C99中定义的新 stdarg可变参数头.要使用它,你需要为你的函数至少有一个固定的参数(在这个例子中count).好的,如果这样你可以在你的函数中有几个可变参数列表(即类似的东西myfunc(int count1, ..., int count2, ...)).糟糕的是你不能拥有纯粹的变量函数(比如myfunc(...)就像旧的格式一样.你仍然可以使用旧的格式使用varargs兼容头.但它更复杂,很少需要,因为你需要类型,但也有一些方法来知道列表已经完成,像count这样的东西很方便(但不是唯一的方法,例如,可以使用'终结符').