2009-08-11 24 views
6

Estoy escribiendo una función en C que toma una cantidad variable de argumentos.C varargs - va_copy issues

size_t myprintf(char *fmt, ...); 

Hasta ahora, muy bien. He decidido que es mejor hacer las cosas de la manera correcta y crear una versión que tome argumentos variables, y otra versión que tome va_list.

size_t myprintf(char *fmt, ...); 
size_t myvprintf(char *fmt, va_list args); 

No es tan difícil de hacer. Excepto my_vprintf() necesita enviar su args a dos funciones diferentes (primero a snprintf() con una longitud de 0 para determinar cuánto espacio necesitamos, luego a sprintf() después de que hayamos asignado esa cantidad de espacio). Lo hago con va_copy.

size_t myvprintf(char *fmt, va_list args) 
{ 
    va_list args2; 
    va_copy(args, args2); 
    // do stuff with args2 
    va_end(args2); 
    // do more stuff with args 
} 

Todo esto está bien y es excelente, pero C99 está un poco mal implementado. Me gustaría, si es posible, que mi código también funcione en C89 y trabajar con tantos compiladores como en tantas plataformas como sea posible. En este momento tengo esto después de #include <stddef.h> pero antes de cualquier código:

#ifndef va_copy 
# ifdef __va_copy 
# define va_copy(a,b) __va_copy(a,b) 
# else /* !__va_copy */ 
# define va_copy(a,b) ((a)=(b)) 
# endif /* __va_copy */ 
#endif /* va_copy */ 

me lleva a creer que ((a)=(b)) es poco fiable, y que tal vez debería utilizar memcpy() o algo similar, pero esto todavía está en el nivel de "Si No soporto C99, espero que funcione "en lugar de" Si no soportas C99, nunca temas "(que es lo que quiero). ¿Hay alguna forma de evitar esta limitación? He visto algunas soluciones - va_list funciones que consumen un argumento y recurse, pasando el va_list dos veces para que se hagan dos copias por separado, etc. - pero no sé qué tan bien funcionarían (y la solución recursiva ganó ' t hacerlo bien si solo quiero llamar al vsnprintf(), ¿verdad?).

Así que me dirijo a ti, usuario de StackOverflow. ¿Hay algo más que pueda hacer para proporcionar la compatibilidad con C89, o los usuarios que no tienen va_copy y __va_copy (algunos pocos entre ellos) simplemente van a tener que aspirarlo y tomarlo?

+0

Es 2009. ¿Por qué todavía necesita la compatibilidad con C89? – stepancheg

+0

Porque VC++ no lo admite (y probablemente no). Y me gusta tenerlo Creo que es algo bueno tener. –

+0

Creo que los MS han llegado tan lejos como para decir que no tienen intención de ir a C99, excepto para elegir las características extrañas que sus clientes desean. – KTC

Respuesta

3

(a)=(b) no es confiable. Incluso pasar dos va_list es (la función pública sería un simple envoltorio) como va_list puede ser algo como:

typedef __va_list_impl va_list[1]; 

para los que haciendo un va_arg en uno será modificar el otro (creo recordar que Solaris utilizar tales tipo de cosas, ah, las ventanas de registro ...). Tristemente, no conozco ninguna manera segura de hacer lo que quieres.

+0

Tenía miedo de esto. Oh bien.Supongo que lo apropiado sería cambiar mi hack-'va_copy' por '#error" Obtener un nuevo compilador "' –

+0

En este caso particular, la asignación en la macro va_copy fallaría, ya que no se puede asignar una matriz a otro. – caf