2010-07-09 15 views
6

Me gustaría definir una función como MACRO. es decir,Definición de macro de tipo función en C

#define foo(x)\ 
#if x>32\ 
x\ 
#else\ 
(2*x)\ 
#endif 

que es,

if x>32, then foo(x) present x 
else, foo(x) present (2*x) 

pero mi queja de GCC:

int a = foo(31); 

creo preprocesador de C debe ser manejar esto correctamente. ya que en tiempo de compilación, conoce x=33. se podría sustituir con foo(33)(2*33)

+1

¿Puedo preguntar por qué necesita una macro para esto? Una función sería mucho más limpia y (tipo) más segura. –

+0

Si sabe lo suficiente como para hacer esta pregunta, debe olvidar que existe la construcción '#define foo (x)', ya que solo le ayudará a escribir el código que, si funciona, lo hace por accidente. – msw

+1

Quiero que el preprocesador C realice la evaluación instaurada del control de flujo de tiempo de ejecución. de esta manera ahorrar tiempo en tiempo de ejecución – richard

Respuesta

2

considerar:

int x = rand() 
int y = foo(x); 

x no se conoce en tiempo de compilación.

+0

Es posible que el compilador determine si una expresión es constante (GCC tiene '__builtin_constant_p', por ejemplo), sin embargo, el preprocesador ISO C no puede. – YoYoYonnY

11

Puede la siguiente manera

#define foo(x) ((x) > 32 ? (x) : (2 * (x))) 

Pero que evalúa x varias veces. En su lugar puede crear una función estática, lo que es más limpio

static int foo(int x) { 
    if(x > 32) 
    return x; 
    return 2 * x; 
} 

A continuación, también son capaces de pasar a cosas foo que tienen efectos secundarios, y tienen el efecto secundario ocurre sólo una vez.

lo que ha escrito es el uso de los #if, #else y #endif directivas del preprocesador, pero hay que usar construcciones del lenguaje si pasar variables a la macro y desea evaluar sus valores. El uso de if y las declaraciones else como en las construcciones de lenguaje reales tampoco funcionan, porque las instrucciones de flujo de control no evalúan los valores. En otras palabras, una instrucción if solo controla el flujo de control ("si A, luego ejecuta B, sino ejecuta C"), sin evaluar a ningún valor.

+0

Seguramente x se evalúa dos veces en ambos casos? –

+1

@Neil el argumento (no el parámetro) solo se evalúa una vez en el caso de función. Intenta llamar a 'int i = 0; foo (i ++); 'Para el caso de función, seré' 1' después. Pero para el caso macro, será '2'. –

+0

Quiero que el preprocesador C haga la evaluación instaurada del control de flujo de tiempo de ejecución. de esta manera ahorrar tiempo en tiempo de ejecución. ¿Por qué dices "#define foo (x) ((x)> 32? (X): (2 * (x))) evalúa x varias veces"? – richard

2
int a = foo(31); 

expande a

int a = if 31>32 
31 
else 
(2*31) 
endif; 

Así es como funcionan las macros C, a través de la sustitución simple, tonto. Si espera que GCC haga algo más complejo o inteligente con ellos, entonces su expectativa es errónea.

Dado que es fácil ver por qué su código no funcionará. Una alternativa que sería suficiente para este ejemplo sería:

#define foo(x) (x > 32 ? x : 2*x) 

Por otro lado, me pregunto si las macros son realmente la herramienta apropiada para tal cosa, para empezar. Simplemente póngalo en la función y el compilador insertará el código si cree que lo acelerará.

+1

Las x en la macro en mi respuesta deben estar entre paréntesis como en la macro de Johannes. De lo contrario, fallará para expresiones complejas.Esta es otra razón para evitar macros – errores simples e inocuos pueden causar errores muy extraños en el camino. –

1

El problema no es sobre la teoría: siempre que, por alguna razón, desee tener una macro que se expanda de manera diferente según el valor de un parámetro que se le pase, y este parámetro es una constante, conocida por la macro preprocesador, no hay ninguna razón por la que no podría funcionar ... para un macroprocesador genérico ... Pero desafortunadamente, cpp no ​​permite la presencia de otros "comandos" de macroprocesador en una definición de macro ...

Así que su

#define foo(x) \ 
#if x>32 \ 
    x  \ 
#else \ 
    2*x \ 
#endif 

no se expande a

#if X>32 
    X 
#else 
    2*X 
#endif 

donde X es el parámetro conocido (por lo que cambiar X a, por ejemplo 31), que requiere otro pase por el preprocesador.

Además, las nuevas líneas se ignoran, aunque son importantes para dicho uso; de lo contrario, el siguiente podría ser considerado como un truco (que necesitan otro paso de procesamiento previo, sin embargo)

#define foo(x,y) \ 
y if x>32 \ 
    x \ 
y else \ 
    2*x \ 
y endif 

que con foo(20,#) produce

# if 20>32 20 # else 2*20 # endif 

que funciona, si sería

# if 20>32 
    20 
# else 
    2*20 
# endif 

... pero no es (y como se dijo, la salida del preprocesador debe ser alimentada al preprocesador nuevamente ...)

Así que mi respuesta es que si necesita estas cosas, no puede usar el preprocesador C; debería usar un preprocesador C poco común (¿no estándar?), o simplemente otro macroprocesador, y si necesita el tipo de cosas que "cpp" tiene que "integrarse" con C, entonces no puede usar una genérica (como M4) tan fácilmente ...

+0

El problema no es sobre la teoría: siempre que, por alguna razón, quiera tener una macro que se expanda de manera diferente según el valor de un parámetro que se le pase, y este parámetro es una constante, conocida por el macroprocesador. Sí, ya entendiste mi punto. pero la solución es tan complicada ¿Hay alguna otra manera? – richard

+0

como dije, no sin cambiar el macro (pre) procesador ... actualmente no conozco el procesador macro similar a cpp con la función que necesita – ShinTakezou

6
#define \ 
    foo(x) \ 
    ({ \ 
     int xx = (x); \ 
     int result = (xx > 32) ? xx : (2*xx); \ 
     result; \ 
    }) 
+0

¿Ha intentado usar esto? –

+0

@Michael: ¡seguro! En Ubuntu 10.04 con gcc. Las macros del kernel de Linux a menudo hacen lo mismo. Y lo usé extensamente en un proyecto mío Linux C++. ¿Qué te parece extraño en mi fragmento de código? –

+0

@Michael: prueba 'grep -C2 -rn '})'. | grep -v Documentación | less' en un árbol de fuentes de Linux y encontrará la misma técnica utilizada en muchos lugares :-) –

Cuestiones relacionadas