2011-08-31 14 views
7
FUNC(param); 

Cuando param es char *, envíe a func_string.¿Cómo implementar una macro genérica en C?

cuando es int, el envío a func_int

Creo que puede ser una solución para esto, ya que los tipos de variables se conocen en tiempo de compilación ..

+0

Incluso si esto fuera posible, sería fugly. C no fue diseñado para eso. Use estructuras y uniones, incluso puede obtener el despacho en tiempo de ejecución de esa manera. –

Respuesta

10

tipos de variables son conocidos por el compilador, pero no a el preprocesador (que ve el código simplemente como texto no estructurado una secuencia de tokens, y realiza solo operaciones simples de reemplazo en él). Así que me temo que no puedes lograr esto con las macros C.

En C++, inventaron plantillas para resolver tales problemas (y más).

+0

¿Hay algún problema en ** C **? – lexer

+2

Esta es una conclusión falsa. El preprocesador no necesita saber tipos de argumentos, si puede organizar una expansión de macro para que el * compilador * pueda realizar el análisis. Vea la respuesta de arnaud576875 cómo resolver esto para el compilador gnu. Además, el preprocesador no ve el código como texto no estructurado, sino como un * token stream *, que es una diferencia importante. –

1

No puede hacer esto con una macro. El valor de Macro se sustituye en tiempo de compilación y no se interpreta. Son solo sustituciones.

11

Esto será posible con C1X pero no en el estándar actual.

Se verá así:

#define cbrt(X) _Generic((X), long double: cbrtl, \ 
          default: cbrt, \ 
          float: cbrtf)(X) 
+0

Como esta pregunta aparece primero en google: ahora es posible usando C11 http://en.cppreference.com/w/c/language/generic –

4

No hay posibilidad de ejecutar los tipos de verificación en tiempo C89/ANSI C, pero no es una extensión de GCC que lo permite. typeof o algo por el estilo si lo recuerdo. Lo vi en el kernel de Linux una vez.

En kernel.h:

#define min(x, y) ({    \ 
typeof(x) _min1 = (x);   \ 
typeof(y) _min2 = (y);   \ 
(void) (&_min1 == &_min2);  \ 
_min1 < _min2 ? _min1 : _min2; }) 

Tome un vistazo a este artículo: GCC hacks in the Linux kernel

Cuando vi por primera vez este hecho, me hizo una pregunta aquí en SO sobre: ​​

min macro in kernel.h

No estoy muy seguro de cómo lo usarías para resolver tu problema, pero vale la pena echarle un vistazo t.

+0

esto no es una verificación de tipo de tiempo de ejecución - como C no se escribe dinámicamente, escriba la información solo está disponible en tiempo de compilación – Christoph

1

Los tipos de variables son realmente conocidos en tiempo de compilación, sin embargo, la expansión de macros tiene lugar antes de la compilación. Sugiero que implemente 2 funciones sobrecargadas en lugar de una macro.

5

Puede probar las características de los tipos.

Por ejemplo, int puede contener un valor negativo, mientras que char* no puede. Así que si ((typeof(param))-1) < 0, param está sin firmar:

if (((typeof(param))-1) < 0) { 
    do_something_with_int(); 
} else { 
    do_something_with_char_p(); 
} 

El compilador optimiza obviamente esto.

probar aquí: http://ideone.com/et0v1

Esto sería aún más fácil si los tipos tenían diferentes tamaños.Por ejemplo, si desea escribir una macro genérico que puede manejar diferentes tamaños de caracteres:

if (sizeof(param) == sizeof(char)) { 
    /* ... */ 
} else if (sizeof(param) == sizeof(char16_t)) { 
    /* ... */ 
} else if (sizeof(param) == sizeof(char32_t)) { 
    /* ... */ 
} else { 
    assert("incompatible type" && 0); 
} 

GCC tiene una función incorporada __builtin_types_compatible_p() que puede comprobar la compatibilidad tipos:

if (__builtin_types_compatible_p(typeof(param), int)) { 
    func_int(param); 
} else if (__builtin_types_compatible_p(typeof(param), char*)) { 
    func_string(param); 
} 

Pruébalo aquí: http://ideone.com/lEmYE

Puede poner esto en una macro para lograr lo que está tratando de hacer:

#define FUNC(param) ({            \ 
    if (__builtin_types_compatible_p(typeof(param), int)) {   \ 
     func_int(param);            \ 
    } else if (__builtin_types_compatible_p(typeof(param), char*)) { \ 
     func_string(param);           \ 
    }                 \ 
}) 

(El ({...}) es un GCC's statement expression, permite que un grupo de declaraciones sea un valor r.

El __builtin_choose_expr() integrado puede elegir la expresión para compilar. Con __builtin_types_compatible_p esto permite desencadenar un error en tiempo de compilación si el tipo de parámetro no es compatible tanto con int y char*: (compilando somehting no válida en este caso)

#define FUNC(param)              \ 
    __builtin_choose_expr(__builtin_types_compatible_p(typeof(param), int) \ 
     , func_int(param)             \ 
     , __builtin_choose_expr(__builtin_types_compatible_p(typeof(param), char*) \ 
      , func_string(param)           \ 
      , /* The void expression results in a compile-time error  \ 
       when assigning the result to something. */    \ 
      ((void)0)              \ 
     )                 \ 
    ) 

Esto es en realidad un ejemplo ligeramente modificado a partir de __builtin_choose_expr docs.

+0

'func_int (x);', 'func_string (x);' y pone todo dentro de 'do {} while (0)' –

+0

Originalmente no encerré el código en 'do {} while()' porque no era una macro ;-) – arnaud576875

+2

-1 'typeof' no es C, sino también una extensión gcc. ¿Qué te hace pensar que una dirección no puede tener el bit 'señal' establecido? –

Cuestiones relacionadas