2011-09-05 12 views
5

consideri il seguente programma C:Come utilizzare varargs in combinazione con i puntatori di funzione in C su Win64?

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

Fondamentalmente, l'idea è di memorizzare una funzione con argomenti variabili in un puntatore alla funzione "generica". Come confronto, ho incluso anche un'altra funzione con elenco di argomenti fissi. Ora vediamo cosa succede quando si esegue questo su Linux x86, amd64 Linux, Win32 e 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 

Perché la funzione dinamica ottiene un valore pari a zero dalla lista di argomenti variabili su Win64, ma non su una qualsiasi delle altre configurazioni ? È qualcosa di simile anche legale? Ho pensato che fosse perché il compilatore non si lamentava.

+1

Sono abbastanza sicuro che questo non è legale; i puntatori di funzione non sono convertibili come questo. –

risposta

5

tuo cod e non è valido Chiamare una funzione variadica richiede un prototipo che indichi che è variadico e il tipo di puntatore a funzione che stai usando non lo fornisce. Affinché la chiamata a non far valere un comportamento indefinito, che avrebbe dovuto lanciare il puntatore dynamic_func come questo per effettuare la chiamata:

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

Grazie soprattutto per la spiegazione. Dato che il mio progetto fa molte di queste chiamate, ora ho scritto un piccolo preprocessore per lanciare i puntatori di funzione nel tipo corretto e funziona :) – smf68

1

Si dovrebbe lavorare con definizioni di funzioni coerenti, anche se ciò significa utilizzare varargs anche se non necessario. Il meglio è essere dettagliati se necessario.

...

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