¿Qué hace ##
en C?
Ejemplo:
typedef struct { unsigned int bit0:1; unsigned int bit1:1; unsigned int bit2:1; unsigned int bit3:1; unsigned int bit4:1; unsigned int bit5:1; unsigned int bit6:1; unsigned int bit7:1; } _io_reg; #define REGISTER_BIT(rg,bt) ((volatile _io_reg*)&rg)->bit##bt
(Sé lo que hace todo además de la parte ##).
Es la concatenación de cadenas , como parte de la macro del preprocesador.
(En este contexto, “cadena” se refiere a un token de preprocesador, por supuesto, o una “cadena de código fuente”, y no una cadena en C).
Se llama el operador de pegado; concatena el texto en bt
con el bit
texto. Así, por ejemplo, si tu invocación de macro fue
REGISTER_BIT(x, 4)
Se expandiría a
((volatile _io_reg*)&x)->bit4
Sin él, no podría poner un argumento de macro directamente al lado del texto en el cuerpo de la macro, porque entonces el texto tocaría el nombre del argumento y se convertiría en parte del mismo token, y se convertiría en un nombre diferente.
El operador ## concatena dos argumentos sin dejar espacios en blanco entre ellos:
#define glue(a,b) a ## b glue(c,out) << "test";
Ese es el operador de pegado de fichas .
Eso es parte de la definición de la macro.
Te permite concatenar cadenas dentro de la macro.
En su caso, puede usar bt
de 7 a 0 de esta manera:
REGISTER_BIT(myreg, 0)
y se ampliará como:
((volatile _io_reg*)& myreg )->bit 0
Sin esto, tendrías que definir la parte de bit
de la macro como uno de los argumentos de la macro:
#define REGISTER_BIT(rg,bt) ((volatile _io_reg*)&rg)->bt
donde el uso sería:
REGISTER_BIT(myreg, bit0)
que es más engorroso.
Esto también te permite construir nuevos nombres.
Supongamos que tiene estas macros:
#define AAA_POS 1 #define AAA_MASK (1 << AAA_POS) #define BBB_POS 2 #define BBB_MASK (1 << BBB_POS)
y desea una macro que extraiga AAA de un vector de bits. Puedes escribirlo así:
#define EXTRACT(bv, field) ((bv & field##_MASK) >> field##_POS)
y luego lo usas así:
EXTRACT(my_bitvector, AAA)
No es una construcción en C, es una característica del preprocesador . En este caso, se pretende evaluar la variable bt
y concatenarla con el prefijo de bit
. Sin los hashes tendrías bitbt
allí, lo que obviamente no funcionaría.
Aquí hay un ejemplo de ffmpeg
, una macro que registra filtros de audio y video:
#define REGISTER_FILTER(X, x, y) \ { \ extern AVFilter ff_##y##_##x; \ if (CONFIG_##X##_FILTER) \ avfilter_register(&ff_##y##_##x); \ }
y el uso puede ser:
REGISTER_FILTER(AECHO,aecho,af); REGISTER_FILTER(VFLIP,vflip,vf);