2009-09-29 11 views
6

Tengo un trillón de llamadas de función my_printf() en un programa enorme. Ahora quiero convertirlos todos para que la función tome un nuevo argumento entero (llámalo x) sin tener que editar los trillones de llamadas. Si my_printf medida limitada a exactamente un argumento de cadena entonces yo podría hacer algo como esto:#define y funciones con argumentos de longitud variable

#define my_printf(str) _my_printf(x,str) 

    void _my_printf(int x,char *str) // changed from my_printf(char *str) 
    { 
     // stuff 
    } 

Pero como my_printf toma un número variable de argumentos no estoy seguro de cómo hacerlo. Se puede hacer?

EDIT: para los que se preguntan por qué debería querer hacer una cosa así, aquí hay un ejemplo relacionado:

#if BELT_AND_BRACES_DIAGNOSTIC_MODE 
    #define function(x) _function(__FILE__,__LINE__,x) 
#else // speed critical optimised mode 
    #define function(x) _function(x) 
#endif 

#if BELT_AND_BRACES_DIAGNOSTIC_MODE 
    void _function(char *file,int line,int x) 
#else 
    void _function(int x) 
#endif 
{ 
    // stuff 
    #if BELT_AND_BRACES_DIAGNOSTIC_MODE 
    if (something_went_wrong) 
    { 
     printf("Cock up in function when called from %s line %d\n",file,line); 
    } 
    #endif 
} 

Respuesta

7

Es posible utilizar macros C99: variadic.

#define my_printf(...) my_printf_(x, __VA_ARGS__) 

Como Microsoft's implementation suppresse arrastran comas, el argumento str se pueden añadir de forma explícita

#define my_printf(str, ...) my_printf_(x, str, __VA_ARGS__) 

pero esto daría lugar a un error de sintaxis en C estándar cuando se invoca sin argumentos variadic

my_printf("foo") 

o un argumento vacío lista

my_printf("foo",) 

Por lo tanto, me gustaría ir con la primera versión.

7

Lo mejor es, por supuesto, hacer de tripas corazón y editar el código. De lo contrario, estás creando un "misterio" que debe ser resuelto por todos los mantenedores futuros del código. Incluso si es solo usted, este es exactamente el tipo de truco inteligente que olvidará. Es una mierda volver, y dejarse confundir por extrañas macros sin sentido.

Dicho esto, si está utilizando una cadena de herramientas de GNU, quizás pueda considerar usar varargs macros.

+0

1 a morder la bala. Con los editores de hoy con soporte de refactorización, etc., debería estar riendo. Diablos, mi editor de programación hace 15 años podía fácilmente hacer una búsqueda global y reemplazar en archivos especificados por comodín en todo un árbol de directorios, con o sin mi vista previa de los resultados primero. (Y si estás pensando en macro, entonces puedes hacerlo a ciegas.) –

+0

Ver mi edición a la pregunta original – Mick

+0

+1. Míralo como una oportunidad de aprendizaje para realmente entender lo que un editor moderno puede hacer (o si has estado aquí lo suficiente, lo que Vim o Emacs pueden hacer, y pueden hacer cosas que Visual Studio solo está capturando). arriba con ...). – AAT

8

Si el código puede ser compilado como código de C99, se puede definir un variadic macro

#define my_printf(str, args...) _my_printf(x, str, ##__VA_ARGS__) 

El preprocesador sustituirá a los argumentos ... y el preprocesador GNU eliminará la coma final en caso de que se invoca la macro solo con el argumento str.

+2

eso es GNU, no C99 - la versión C99 leería 'define my_printf (str, ...) _my_printf (x, __VA_ARGS __)'; tenga en cuenta que debe proporcionar por lo menos un argumento – Christoph

+0

también, usted y yo olvidamos pasar 'str'; Creo que el mejor enfoque sería soltar el 'explícito' explícito por completo y simplemente usar 'define my_printf (...) _my_printf (x, __VA_ARGS __)' para que pueda llamarlo sin los varargs de la función incluso en la versión C99 – Christoph

+0

el problema ahora está resuelto Estoy usando dev-studio 2008 y la cosa __VA_ARGS__ funcionó bien, pero no estoy seguro de qué respuesta marcar como correcta porque ninguno de ellos es realmente perfecto. La respuesta de unwind implica que necesito estar usando GNU y la respuesta de phillipe también tiene errores. – Mick

0

Si my_printf ya toma una cantidad variable de argumentos, no estoy seguro de por qué necesita envolver 'un argumento más' en una macro ... Simplemente inserte las nuevas llamadas con el argumento adicional y termine con ellas; las llamadas antiguas deberían seguir funcionando como se esperaba.

2

No con las macros estándar C89, no se puede. Sin embargo se puede obtener el mismo efecto usando funciones, rompiendo la parte principal de su función my_printf en una función vmy_printf, análogo a la norma vprintf:

#include <stdarg.h> 

int vmy_printf(int x, const char *format, va_list ap) 
{ 
    /* main body of my_printf goes here, taking its varargs from ap */ 
} 

/* new_my_printf(), for callers who know about the x parameter */ 
int new_my_printf(int x, const char *format, ...) 
{ 
    int n; 
    va_list ap; 

    va_start(ap, format); 
    n = vmy_printf(x, format, ap); 
    va_end(ap); 

    return n; 
} 

/* my_printf(), for the old callers who don't know about x */ 
int my_printf(const char *format, ...) 
{ 
    int n; 
    va_list ap; 

    va_start(ap, format); 
    n = vmy_printf(DEFAULT_X, format, ap); 
    va_end(ap); 

    return n; 
} 

(Este tipo de cosas es qué los v. .. versiones de toda la norma varargs existen funciones)

0

Una solución simple a este problema es ...

#define my_printf(x) printf x 

(tenga en cuenta los apoyos perdidos)

llamarlo, uso:

my_printf((any number of arguments)) 

(tenga en cuenta los apoyos dobles)

Cuestiones relacionadas