Concatenar int a string usando C Preprocessor

90

Estoy tratando de averiguar cómo puedo concatenar un #define'd int a un #define' d string usando el preprocesador C. Mi compilador es GCC 4.1 en CentOS 5. La solución también debería funcionar para MinGW.

Me gustaría agregar un número de versión a una cadena, pero la única forma en que puedo hacer que funcione es hacer una copia del número de versión definido como cadenas.

Lo más cercano que pude encontrar fue un método para citar argumentos macro, pero no funciona para #defines

Esto no funciona.

#define MAJOR_VER 2
#define MINOR_VER 6
#define MY_FILE "/home/user/.myapp" #MAJOR_VER #MINOR_VER

Tampoco funciona sin la #s porque los valores son números y se expandiría a "/home/user/.myapp" 2 6, que no es C válido .

Esto funciona, pero no me gusta tener copias de la versión definida porque también las necesito como números.

#define MAJOR_VER 2
#define MINOR_VER 6
#define MAJOR_VER_STR "2"
#define MINOR_VER_STR "6"
#define MY_FILE "/home/user/.myapp" MAJOR_VER_STRING MINOR_VER_STRING
jonescb
fuente
3
Posible duplicado de Convertir un token de preprocesador en una cadena
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Respuestas:

172

Pregunta clásica del preprocesador C ...

#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)

#define MAJOR_VER 2
#define MINOR_VER 6
#define MY_FILE "/home/user/.myapp" STR(MAJOR_VER) STR(MINOR_VER)

El nivel adicional de indirección permitirá al preprocesador expandir las macros antes de que se conviertan en cadenas.

Lindydancer
fuente
3
STR () en este caso dará una cadena estrecha. ¿Hay alguna variación para convertir esto en una cadena ancha?
gkns
5
No podría decir cuántas veces lo busqué en Google y copié esta respuesta exacta, pero estará en dos dígitos
MightyPork
1
Se requiere el primer "STR_HELPER" porque '#' solo funciona con un argumento macro. Me tomó un tiempo darme cuenta de eso ..
clarkttfu
1
@clarkttfu, una especie de - sí, #solo funciona con argumentos macro. Sin embargo, la STR_HELPERmacro es necesaria para evitar convertir la macro MAJOR_VERen la cadena "MAJOR_VAR", donde queremos que sea el resultado "2".
Lindydancer
13

Una forma de trabajo es escribir MY_FILE como una macro paramétrica:

#define MY_FILE(x,y) "/home..." #x #y

EDITAR: Como señaló "Lindydancer", esta solución no expande las macros en los argumentos. Una solución más general es:

#define MY_FILE_(x,y) "/home..." #x #y
#define MY_FILE(x,y) MY_FILE_(x,y)
Giuseppe Guerrini
fuente
1
En mi sincera opinión, esta es la mejor respuesta y es mucho más simple que las otras sugerencias. ¡Me sorprende que no haya obtenido una mejor calificación!
osirisgothra
5
Es una solución limpia que, lamentablemente, no funciona. Si el argumento pasado a MY_FILEson macros, digamos Ay B, esta macro se expandirá a "/home..." "A" "B".
Lindydancer
2

Puedes hacerlo con BOOST_PP_STRINGIZE :

#define MAJOR_VER 2
#define MINOR_VER 6
#define MY_FILE "/home/user/.myapp" BOOST_PP_STRINGIZE(MAJOR_VER) BOOST_PP_STRINGIZE(MINOR_VER)
Maxim Egorushkin
fuente
28
Me hace sonreír cómo la gente lanza Boost a todo.
Frerich Raabe
4
@Frerich: Llevando su argumento al extremo, la gente debería escribir sus propios compiladores primero en código de máquina en bruto, en lugar de lanzar g ++ en todo ... No tiene sentido reinventar la rueda. Los buenos programadores escriben código, los grandes reutilizan.
Maxim Egorushkin
@jonescb: simplemente abre el encabezado de impulso y compruébalo por ti mismo.
Maxim Egorushkin
10
Sí, lo intenté. Funcionó, pero usar un encabezado Boost en un programa C me parece un poco extraño.
jonescb
1
Oh, mi mal, no me di cuenta de la Cetiqueta.
Maxim Egorushkin