Frage

Betrachten Sie das folgende C -Programm:

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

Grundsätzlich ist es die Idee, eine Funktion mit variablen Argumenten in einem "generischen" Funktionszeiger zu speichern. Zum Vergleich habe ich auch eine andere Funktion mit fester Argumentliste aufgenommen. Sehen Sie nun, was passiert, wenn Sie dies unter X86 Linux, AMD64 Linux, Win32 und Win64 ausführen:

$ 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

Warum erhält die dynamische Funktion einen Nullwert aus der variablen Argumentliste auf Win64, jedoch nicht auf einer der anderen Konfigurationen? Ist so etwas überhaupt legal? Ich nahm an, dass es sich nicht um den Compiler handelte.

War es hilfreich?

Lösung

Ihr Code ist nicht gültig. Das Aufrufen einer variadischen Funktion erfordert einen Prototyp, der angibt, dass es sich um variadisch handelt, und der von Ihnen verwendete Funktionzeigertyp liefert dies nicht. Damit der Anruf nicht undefiniertes Verhalten aufgerufen hatte, müssten Sie das wirken dynamic_func Zeiger wie diesen, um den Anruf zu tätigen:

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

Andere Tipps

Sie sollten mit konsistenten Funktionsdefinitionen arbeiten, auch wenn dies bedeutet, Varargs zu verwenden, auch wenn dies nicht erforderlich ist. Das Beste ist, so ausführlich wie nötig zu sein.

...

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);
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top