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

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.


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)

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)

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.