你不能按照你描述的方式去做。
C 调用约定是让调用者将参数放在堆栈上,但它没有放置任何关于类型的信息,因此被调用者必须有办法找到它(至少是变量的大小)。
因此,您必须传递类型。
在某些情况下,您可以预测类型(例如:一个计数器后跟一些整数,等等),但通常您将它编码为参数。您可以像 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);
}
此示例使用 C99 中定义的新stdarg 可变标头。要使用它,您的函数至少需要一个固定参数(在本例中为count
)。如果这样你可以在你的函数中有几个可变参数列表(即类似的东西myfunc(int count1, ..., int count2, ...)
),那将是一件好事。坏事是你不能有一个纯粹的可变参数函数(即像 myfunc(...) 这样的旧格式。你仍然可以使用 varargs 兼容性标头使用旧格式。但它更复杂,很少需要,因为您需要类型,但还需要某种方法来知道列表已完成,并且 count 之类的东西很方便(但不是唯一的方法,例如可以使用“终止符”)。