Publi

Conocer las macros definidas en GCC (incluso las predefinidas), vamos, los #defines

gccmod

En ocasiones, nos viene muy bien conocer las macros que están en uso en un proyecto. Por ejemplo, para ver si se cumple un #ifdef/#ifndef qué vale un #define un poco complicado… o incluso para ver las macros que se definen automáticamente justo antes de compilar, por el propio compilador o alguna biblioteca.

La clave está en:

$ gcc -dM -E [archivo de entrada]

En este caso:

  • -dM : varía el comportamiento de la salida de gcc. En este caso -d puede ir seguido de otros caracteres, pero si va seguido de M, escribirá en pantalla sólo las macros definidas (#defines). Podemos no poner este parámetro, para ver cómo queda nuestro programa justo antes de realizar la compilación (es decir, con todas las macros aplicadas)
  • -E : define el punto en el que gcc parará. En este caso, con -E pararemos justo después de procesar las macros. Es decir, con esta línea no estaremos generando ejecutable ni compilando nada. Sólo devolvemos las macros y salimos de gcc.

Ver macros generadas para un programa

Así si hacemos:

$ gcc -dM -E ejemplo.c

Devolvería algo como:

#define _IO_CURRENTLY_PUTTING 0x800
#define __DBL_MIN_EXP__ (-1021)
#define _IO_peekc_unlocked(_fp) (_IO_BE ((_fp)->_IO_read_ptr >= (_fp)->_IO_read_end, 0) && __underflow (_fp) == EOF ? EOF : *(unsigned char *) (_fp)->_IO_read_ptr)
#define __UINT_LEAST16_MAX__ 65535
#define __ATOMIC_ACQUIRE 2
#define __FLT_MIN__ 1.17549435082228750797e-38F
#define _IO_UNITBUF 020000
#define __UINT_LEAST8_TYPE__ unsigned char
#define __flexarr []
#define _IO_FLAGS2_USER_WBUF 8
#define __S64_TYPE long int
#define __stub_fchflags
#define __SQUAD_TYPE long int
#define __INTMAX_C(c) c ## L
—– (y mucho más)

Y eso será porque hemos incluido stdio.h en nuestro programa en C.

Ver macros por defecto de gcc

Para eso, tendríamos que hacer lo mismo de antes, pero sin archivo de entrada. En este caso podríamos utilizar un archivo vacío, o hacer lo siguiente:

$ gcc -dM -E –

Con esto, le estamos diciendo que coja el archivo de entrada de stdin (la entrada estándar), y al mismo tiempo le estamos diciendo que coja como entrada /dev/null (por medio de una redirección de archivo a entrada estándar)

Esto, nos devolvería algo como:

#define __DBL_MIN_EXP__ (-1021)
#define __UINT_LEAST16_MAX__ 65535
#define __ATOMIC_ACQUIRE 2
#define __FLT_MIN__ 1.17549435082228750797e-38F
#define __UINT_LEAST8_TYPE__ unsigned char
#define __INTMAX_C(c) c ## L
#define __CHAR_BIT__ 8
#define __UINT8_MAX__ 255
#define __WINT_MAX__ 4294967295U
#define __ORDER_LITTLE_ENDIAN__ 1234
#define __SIZE_MAX__ 18446744073709551615UL
#define __WCHAR_MAX__ 2147483647
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1
… (y mucho más)

De hecho esta salida contendrá menos cosas que la salida anterior, ya que la anterior será la combinación de las macros por defecto de GCC más las macros de las bibliotecas incluidas.

Con estas macros podemos conocer cosas como la arquitectura para la que estamos compilando (imagina que queremos saber si el programa es para 32 o 64bits), la plataforma (Windows, Mac, Linux, …), la versión del compilador (puede que haya fallos en alguna versión, o que no tenga ciertas cosas implementadas…), optimizaciones de CPU (SSE, SSE2, …)?, tamaños de datos, y muchas cosas más.

g++

Y si todo esto vale para C, para C++ también, cambiamos gcc, por g++ y listo.

Leave a Reply