如何在Win64上使用varargs和C中的函数指针?
问题描述:
考虑下面的C程序:如何在Win64上使用varargs和C中的函数指针?
#include <stdio.h>
#include <stdarg.h>
typedef void (callptr)();
static void fixed(void *something, double val)
{
printf("%f\n", val);
}
static void dynamic(void *something, ...)
{
va_list args;
va_start(args, something);
double arg = va_arg(args, double);
printf("%f\n", arg);
}
int main()
{
double x = 1337.1337;
callptr *dynamic_func = (callptr *) &dynamic;
dynamic_func(NULL, x);
callptr *fixed_func = (callptr *) &fixed;
fixed_func(NULL, x);
printf("%f\n", x);
}
基本上,这个想法是存储与可变参数的函数在一个“通用”函数指针。作为比较,我还包含了另一个带有固定参数列表的函数。现在看到在x86的Linux,AMD64的Linux,Win32和Win64中运行这个时候发生了什么:
$ gcc -m32 -o test test.c
$ file test
test: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.9, not stripped
$ ./test
1337.133700
1337.133700
1337.133700
$ gcc -o test test.c
$ file test
test: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.9, not stripped
$ ./test
1337.133700
1337.133700
1337.133700
C:\>gcc -o test.exe test.c
C:\>file test.exe
test.exe: PE32 executable for MS Windows (console) Intel 80386 32-bit
C:\>test.exe
1337.133700
1337.133700
1337.133700
C:\>x86_64-w64-mingw32-gcc -o test.exe test.c
C:\>file test.exe
test.exe: PE32+ executable for MS Windows (console) Mono/.Net assembly
C:\>test.exe
0.000000
1337.133700
1337.133700
为什么动态功能得到Win64上的变量参数列表零值,而不是在任何其他配置的?这样的事情甚至合法吗?我认为这是因为编译器没有抱怨。
答
你的鳕鱼e无效。调用一个可变参数函数需要一个原型来表明它是可变的,并且你正在使用的函数指针类型没有提供这个。为了使呼叫不调用不确定的行为,你就必须投下dynamic_func
指针这样拨打电话:
((void (*)(void *, ...))dynamic_func)(NULL, x);
+0
特别感谢您的解释。由于我的项目做了很多这些调用,现在我写了一个小型的预处理器来将函数指针转换为正确的类型,并且它可以工作:) – smf68
答
你应该使用一致的函数定义,即使这意味着即使不需要使用可变参数。最好的是如所需要的那样冗长。
...
typedef void myfunc_t(void *, ...);
...
myfunc_t dynamic;
void dynamic(void * something, ...)
{
...
}
...
int main()
{
double x = 1337.1337;
myfunc_t *callnow;
callnow = &dynamic;
callnow(NULL, x);
printf("%f\n", x);
}
我敢肯定,这是不合法的;函数指针不能像这样转换。 –