如何在Win64上使用Varargs和C中的函数指针一起使用?

考虑以下C程序:

#include  #include  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); } 

基本上,我们的想法是在“generics”函数指针中存储一个带有变量参数的函数。 作为比较,我还包括另一个具有固定参数列表的函数。 现在看看在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上的变量参数列表中获取零值,而不是在任何其他配置上? 这样的事情是否合法? 我以为这是因为编译器没有抱怨。

您的代码无效。 调用可变参数函数需要一个原型来指示它是可变参数,并且您正在使用的函数指针类型不提供此function。 为了使调用不调用未定义的行为,您必须像这样dynamic_func调用dynamic_func指针来进行调用:

 ((void (*)(void *, ...))dynamic_func)(NULL, x); 

您应该使用一致的函数定义,即使这意味着即使不需要也使用varargs。 最好的是尽可能详细。

 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); }