2011-09-05 61 views
5

考慮下面的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上的變量參數列表零值,而不是在任何其他配置的?這樣的事情甚至合法嗎?我認爲這是因爲編譯器沒有抱怨。

+1

我敢肯定,這是不合法的;函數指針不能像這樣轉換。 –

回答

5

你的鱈魚e無效。調用一個可變參數函數需要一個原型來表明它是可變的,並且你正在使用的函數指針類型沒有提供這個。爲了使呼叫不調用不確定的行爲,你就必須投下dynamic_func指針這樣撥打電話:

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

特別感謝您的解釋。由於我的項目做了很多這些調用,現在我寫了一個小型的預處理器來將函數指針轉換爲正確的類型,並且它可以工作:) – smf68

1

你應該使用一致的函數定義,即使這意味着即使不需要使用可變參數。最好的是如所需要的那樣冗長。

...

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