[C con Clase] macros en C/C++

Steven Davidson srd4121 en njit.edu
Lun Sep 15 23:08:50 CEST 2008


Hola Leonel,

Leonel Florín Selles wrote:
> hola amigos:
> 
> bueno les escribo para hacerle una pregunta a la cual le conoscon la
> respuesta, pero le conosco la respuesta porque, bueno, es decir,
> tengo duda sobre un tema, el cual me lo explicaron, bueno me dijero,
> esto es asi y ya, no me explicaron. la cosa es
> 
> las macros son creadas con la directiva de procesador
> 
> #define
> 
> lo que el texto de reemplazo es una operación, la cual puede tener
> argumentos o no, me sentro en macros con argumentos, entonces, para
> poder pasarle un argumento a la macro tengo que poner () al final
> del nombre del identificador de la macro, es decir
> 
> ejemplo:
> 
> #define AREA(b) 3.14 * (x) * (x)
> 

Esta macro no está bien definida. Sospecho que quieres que 'b' sea el 
parámetro o argumento que es 'x'. La definición debería ser la siguiente:

#define AREA(b) 3.14 * (b) * (b)

Ahora, cualquier expresión pasada a 'AREA()' como argumento sustituye a 'b'.

> y para que funciones
> 
> area = AREA(2);
> 
> ahora, lo que no tengo entendido es, cada vez que valla a pasarle
> argumentos a la macro tengo que utilizar esta forma
> 
> #define identificador(variable) ..........
> 

En primer lugar, esto es la definición de la macro. En segundo lugar, no 
sugiero pensar que son "variables", sino más bien constantes.

Para usar la macro, debemos escribir el identificador seguido 
inmediatamente por la apertura de paréntesis. Si existe algún carácter 
blanco entre el nombre y el paréntesis, entonces no se considera una 
macro sino posiblemente una función de C/C++. Por ejemplo,

int area = AREA(2);   // usamos la macro AREA()

int area = AREA (3);  // no "llamamos" a una macro

> y porque......
> 

Todo esto se basa en la gramática establecida por el lenguaje de C y C++.

> otra cosa, como sabe #define, que tiene que sustituir a (b) por el
> valor 2, si #define lo que hace es sustituri a el identificador que
> es la constante simbolica por el texto de reemplazo que son los
> simbolos que ponemos despues del identificador en #define.
> 

No veo que el comportamiento de la sustitución que hace el precompilador 
tenga que ver con la sustitución del argumento 'b'. O sea, lo uno no 
quita lo otro.

El precompilador realiza la sustitución cuando se usa la macro. Por 
ejemplo, usando mi definición de 'AREA()', tenemos esto:

area = AREA(2);

El precompilador realiza lo siguiente:

area = 3.14 * (b) * (b);

A su vez, el precompilador sustituye los 'b' por 2. Esto es,

area = 3.14 * (2) * (2);

Podrías pensar que existe dos sustituciones, pero el precompilador 
seguramente hace ambas en un solo paso. El precompilador es muy simple, 
pero no tan "tonto".

> ya probe en el compilador y si no es asi no lo coje, para mi
> entender, esto se procesa como si fuera una función al pasarle la
> lista de argumentos que tienen que estar encerrado dentro de
> parentesis.
> 

No asocies las macros con las funciones de C/C++, porque posiblemente 
empieces a cometer muchos errores. De hecho, la definición de la macro 
que nos diste tiene 2 errores: uno ya te lo corregí. El otro error está 
en que deberías agrupar la definición usando paréntesis. Esto es,

#define AREA(b) (3.14 * (b) * (b))

Si no haces esto, podemos tener problemas que implican comportamientos 
muy raros. Por ejemplo,

res = 5 / AREA(3);

Sin los paréntesis, obtendríamos lo siguiente:

res = 5 / 3.14 * (3) * (3);

El problema es que se hará la división primero y luego las 
multiplicaciones. Sin embargo, esto no es lo que queremos. Con los 
paréntesis, sí conseguimos dividir 5 entre el resultado de 'AREA()'. 
Esto es,

res = 5 / (3.14 * (3) * (3));

Lo mismo sucede con esta condición:

int x;
...
// Si el área es 0
if( !AREA(x) )  ...

Sin los paréntesis, acabaríamos con lo siguiente:

if( !3.14 * (x) * (x) )  ...

El operador ! tiene mayor precedencia que las multiplicaciones. Esto es 
muy diferente a lo que queremos. Usando paréntesis, logramos nuestro 
objetivo:

if( !(3.14 * (x) * (x)) )  ...

> bueno, yo se que eso es asi por regla, y lo comprendo y lo utilizo,
> pero alguien tiene una explicación mejor.
> 

No sé que otra explicación quieres que haya. Si preguntas acerca de la 
lógica que sigue el preprocesador para llevar a cabo la sustitución o, 
como se suele decir, la expansión, entonces sinceramente no hay una 
respuesta exacta, ya que un preprocesador puede ser diferente a otro. Lo 
que sí tienen en común es el resultado de las expansiones.

Ten presente que el preprocesador modifica el código fuente; 
básicamente, reprograma tu programa. Como el código fuente no es más que 
un fichero de texto, el preprocesador se basa en manejar caracteres y 
cadenas de caracteres. La definición de la macro es una mera cadena que 
el preprocesador guarda en su programa. Lo normal es que el 
preprocesador tiene una tabla de símbolos y definiciones. Por ejemplo,

  Símbolo |    Definición    | Argumentos
---------+------------------+------------
   AREA   | 3.14 * (b) * (b) |      b


Espero que esto te oriente y sea lo que nos has pedido.

Steven





Más información sobre la lista de distribución Cconclase