我想创建一个指向函数的函数指针,该函数将处理采用可变参数列表的函数的案例子集。用例是将一个...
接受特定参数列表的函数强制转换为接受特定参数列表的函数,因此您可以在不处理va_list
和朋友的情况下处理可变参数。
在下面的示例代码中,我将一个带有可变参数的函数转换为一个带有硬编码参数列表的函数(反之亦然)。这有效(或恰好有效),但由于使用的调用约定,我不知道是否是巧合。(我在两个不同的基于 x86_64 的平台上进行了尝试。)
#include <stdio.h>
#include <stdarg.h>
void function1(char* s, ...)
{
va_list ap;
int tmp;
va_start(ap, s);
tmp = va_arg(ap, int);
printf(s, tmp);
va_end(ap);
}
void function2(char* s, int d)
{
printf(s, d);
}
typedef void (*functionX_t)(char*, int);
typedef void (*functionY_t)(char*, ...);
int main(int argc, char* argv[])
{
int x = 42;
/* swap! */
functionX_t functionX = (functionX_t) function1;
functionY_t functionY = (functionY_t) function2;
function1("%d\n", x);
function2("%d\n", x);
functionX("%d\n", x);
functionY("%d\n", x);
return 0;
}
这是未定义的行为吗?如果是的话,任何人都可以举一个这样的平台示例,或者在给定更复杂的用例的情况下,如何调整我的示例以使其失败?
编辑:为了解决此代码会因更复杂的参数而中断的含义,我扩展了我的示例:
#include <stdio.h>
#include <stdarg.h>
struct crazy
{
float f;
double lf;
int d;
unsigned int ua[2];
char* s;
};
void function1(char* s, ...)
{
va_list ap;
struct crazy c;
va_start(ap, s);
c = va_arg(ap, struct crazy);
printf(s, c.s, c.f, c.lf, c.d, c.ua[0], c.ua[1]);
va_end(ap);
}
void function2(char* s, struct crazy c)
{
printf(s, c.s, c.f, c.lf, c.d, c.ua[0], c.ua[1]);
}
typedef void (*functionX_t)(char*, struct crazy);
typedef void (*functionY_t)(char*, ...);
int main(int argc, char* argv[])
{
struct crazy c =
{
.f = 3.14,
.lf = 3.1415,
.d = -42,
.ua = { 0, 42 },
.s = "this is crazy"
};
/* swap! */
functionX_t functionX = (functionX_t) function1;
functionY_t functionY = (functionY_t) function2;
function1("%s %f %lf %d %u %u\n", c);
function2("%s %f %lf %d %u %u\n", c);
functionX("%s %f %lf %d %u %u\n", c);
functionY("%s %f %lf %d %u %u\n", c);
return 0;
}
它仍然有效。谁能指出什么时候会失败的具体例子?
$ gcc -Wall -g -o varargs -O9 varargs.c
$ ./varargs
this is crazy 3.140000 3.141500 -42 0 42
this is crazy 3.140000 3.141500 -42 0 42
this is crazy 3.140000 3.141500 -42 0 42
this is crazy 3.140000 3.141500 -42 0 42