Concatenar int para string usando o pré-processador C

90

Estou tentando descobrir como posso concatenar um #define'd int em uma #definestring' d usando o pré-processador C. Meu compilador é o GCC 4.1 no CentOS 5. A solução também deve funcionar para o MinGW.

Gostaria de anexar um número de versão a uma string, mas a única maneira de fazer funcionar é fazer uma cópia do número da versão definido como strings.

A coisa mais próxima que consegui encontrar foi um método de citar argumentos de macro, mas não funciona para #defines

Isso não funciona.

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

Também não funciona sem o #s porque os valores são números e ele se expandiria para "/home/user/.myapp" 2 6, o que não é C válido .

Isso funciona, mas eu não gosto de ter cópias das definições de versão porque eu preciso delas como números também.

#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
fonte
3
Possível duplicata de Converter um token de pré-processador em uma string
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功 05 de

Respostas:

168

Pergunta clássica do pré-processador 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)

O nível extra de indireção permitirá que o pré-processador expanda as macros antes de serem convertidas em strings.

Lindydancer
fonte
3
STR () neste caso fornecerá uma string Narrow. Existe uma variação para converter isso em uma corda larga?
gkns
4
Não consegui dizer quantas vezes pesquisei no Google e copiei a resposta exata, mas vai estar em dois dígitos
MightyPork
O primeiro "STR_HELPER" é necessário porque '#' só funciona com um argumento de macro. Levei algum tempo para descobrir isso ..
clarkttfu
@clarkttfu, mais ou menos - sim, #só funciona com argumentos de macro. No entanto, a STR_HELPERmacro é necessária para evitar a transformação da macro MAJOR_VERna string "MAJOR_VAR", onde queremos que o resultado esteja "2".
Lindydancer
12

Uma maneira prática é escrever MY_FILE como uma macro paramétrica:

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

EDIT: Conforme observado por "Lindydancer", esta solução não expande macros em argumentos. Uma solução mais geral é:

#define MY_FILE_(x,y) "/home..." #x #y
#define MY_FILE(x,y) MY_FILE_(x,y)
Giuseppe Guerrini
fonte
1
Na minha opinião sincera, esta é a melhor resposta e é muito mais simples do que as outras sugestões. Estou surpreso que não tenha obtido uma classificação melhor!
osirisgothra
5
É uma solução limpa que, infelizmente, não funciona. Se o argumento passado para MY_FILEforem macros, diga Ae B, essa macro se expandirá para "/home..." "A" "B".
Lindydancer,
2

Você pode fazer isso com 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
fonte
28
Me faz rir como as pessoas usam Boost em tudo.
Frerich Raabe
4
@Frerich: Levando seu argumento ao extremo, as pessoas deveriam escrever seus próprios compiladores primeiro em código de máquina bruto, em vez de jogar g ++ em tudo ... Não adianta reinventar a roda. Bons programadores escrevem código, ótimos reutilizam.
Maxim Egorushkin
@jonescb: basta abrir o cabeçalho do boost e ver por si mesmo.
Maxim Egorushkin
10
Sim, eu tentei. Funcionou, mas usar um cabeçalho Boost em um programa C parece meio estranho para mim.
jonescb
1
Oh, meu mal, não notei Ctag.
Maxim Egorushkin