Pregunta

Considere el siguiente programa 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);
}

Básicamente, la idea es almacenar una función con argumentos variables en un puntero de función "genérico". Como comparación, también he incluido otra función con una lista de argumentos fijos. Ahora vea qué sucede al ejecutar esto en X86 Linux, AMD64 Linux, Win32 y 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

¿Por qué la función dinámica obtiene un valor cero de la lista de argumentos variables en Win64, pero no en ninguna de las otras configuraciones? ¿Es algo así incluso legal? Asumí que es porque el compilador no se quejó.

¿Fue útil?

Solución

Su código no es válido. Llamar a una función variádica requiere un prototipo que indique que es variádico, y el tipo de puntero de función que está utilizando no proporciona esto. Para que la llamada no invoque un comportamiento indefinido, tendría que lanzar el dynamic_func puntero como este para hacer la llamada:

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

Otros consejos

Debe trabajar con definiciones de funciones consistentes, incluso si eso significa usar varargs incluso si no es necesario. Lo mejor es ser tan detallado como sea necesario.

...

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);
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top