[C con Clase] Preprocesador

Steven Davidson steven en conclase.net
Vie Mar 16 17:59:10 CET 2007


Hola Alejandro,

El pasado 2007-03-16 15:45:34, Alejandro escribió:

A> Hola, tengo tres dudas con el capítulo del preprocesador:
A>  
A> 1. ¿Puedo definir variables dentro de un #if o #elif?
A>     Ej:
A>         .....
A>         #ifndef MOSTRAR
A>             #define MOSTRAR(a) a
A>             int k = 18;
A>         #endif
A>         .....
A>       
A>     ¿Es correcto?
A>  

Sí. Se puede hacer. Recuerda que las directivas del precompilador no son controladas por el compilador. Por lo tanto, cualquier escrito que el preprocesador se encuentre, que no sea una directiva o algna macro a expandir, se dejará intacto e in situ para ser analizado y traducido por el compilador.

A> 2. ¿Qué hace la directiva #line? Algún ejemplo, por favor.
A>  

Bueno, como explica el curso, ya no se usa. Típicamente, aquellas herramientas que generan código C/C++ usaban esta directiva para modificar el número de línea del código y optativamente el fichero originario. Por ejemplo,

// main.c

int main()
{
  #line 100 "defs.c"
  int b;
  float f = var;
  ...
}

Obviamente, tendremos un error con la inicialización de 'f' en la línea 7 de "main.c". Sin embargo, algo indicar #line, el compilador informa del error pero no la línea ni fichero que pensamos. El compilador dará el mensaje:

Identificador inválido: 'var' en la línea 101 en "defs.c"

A> 3. ¿Y la #pragma? Ejemplos también, si es posible.
A>  

La directiva #pragma realmente sirve para programar el compilador específico que estés usando. Por ejemplo,

#pragma argsused
int main( int argc, char **args )
{
  cout << "hola mundo\n";

  return 0;
}

Bajo los compiladores de Borland, el argumento 'argsused' de la directiva #pragma funciona. Si no usáramos #pragma, Borland nos daría un aviso relacionado con los argumentos de la función, ya que los declaramos, pero no los usamos. Usando esta directiva se suprime este aviso en la compilación.

Otro ejemplo,

struct algo
{
  char car;
  short num;
  char letra;
};

Seguramente la organización de los datos miembros de 'algo' es la siguiente:

'car'   comienza en el byte #0 y ocupa 1 byte,
'num'   comienza en el byte #1 y ocupa 2 bytes,
'letra' comienza en el byte #3 y ocupa 1 byte,

La estructura 'algo' ocupa 4 bytes, si suponemos que la agrupación es de 4 bytes.

Podemos cambiar el alineamiento de los bytes con 'pack()', que suele ser una opción popular implementada por varios compiladores:

#pragma pack(2)
struct algo
{
  char car;
  short num;
};

Ahora, la organización se basa en un alineamiento de 2 bytes que será:

'car'   comienza en el byte #0 y ocupa 1 byte,
'num'   comienza en el byte #2 y ocupa 2 bytes,
'letra' comienza en el byte #4 y ocupa 1 byte,

La estructura 'algo' ocupa 6 bytes.

Como ahora todo se "empaqueta" en grupos de 2 bytes, 'num' no cabe en el primer bloque, y por tanto aparece en el segundo.


Otro ejemplo popular es 'once' para indicar que un fichero de cabecera sólo se incluye la primera vez. Por ejemplo,

// "prototipos.h"
#pragma once

int func();
double g();

La manera estándar de hacer lo anterior es usando otras directivas del precompilador. Por ejemplo,

// "prototipos.h"

#ifndef _PROTOTIPOS_H_
#define _PROTOTIPOS_H_

int func();
double g();

#endif


Nuevamente, recuerda que ni 'argsused' ni 'pack()' ni 'once' son estándares. Algunos compiladores las aceptan, pero otros no.


Espero haber aclarado las inquietudes que tenías.

Steven


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