Tentando entender o pré-processador C
-
17-09-2020 - |
Pergunta
Por que é que estes blocos de código produzir resultados diferentes?
Algum código:
#define PART1PART2 works
#define STRINGAFY0(s) #s
#define STRINGAFY1(s) STRINGAFY0(s)
caso 1:
#define GLUE(a,b,c) a##b##c
STRINGAFY1(GLUE(PART1,PART2,*))
//yields
"PART1PART2*"
caso 2:
#define GLUE(a,b) a##b##*
STRINGAFY1(GLUE(PART1,PART2))
//yields
"works*"
caso 3:
#define GLUE(a,b) a##b
STRINGAFY1(GLUE(PART1,PART2*))
//yields
"PART1PART2*"
Eu estou usando MSVC++ a partir de VS.net 2005 sp1
Editar:atualmente, ele é a minha crença de que o pré-processador funciona assim durante a expansão de macros:Passo 1:- tomar o corpo - remove qualquer espaço em branco em torno ## operadores - analisar a cadeia, no caso em que um identificador é encontrado que coincide com o nome de um parâmetro:-se ele está ao lado de uma ## operador, substituir o identificador com o valor literal do parâmetro (por exemplo,a seqüência de caracteres passada) -se NÃO estiver ao lado de um ## operador, execute toda esta explicação processo sobre o valor do primeiro parâmetro e, em seguida, substituir o identificador com que resultado.(ignorando o stringafy único '#' caso atm) -remova todos os ## operadores
Passo 2:- assumir que a seqüência de caracteres resultante e analisá-lo para qualquer macros
agora, desde que eu acredito que todos os 3 casos, deve produzir exatamente a mesma seqüência de caracteres resultante:
PART1PART2*
e, portanto, após a etapa 2, deve resultar em
funciona*
mas pelo menos deve resultar na mesma coisa.
Solução
casos 1 e 2 não têm nenhum comportamento definido desde o seu estão tentando colar um *
em um pré-processamento do token.De acordo com as normas da associação do seu pré-processador isso tenta colar juntos os tokens PART1PART2
(ou apenas PART2
) e *
.No seu caso, isso provavelmente falhará silenciosamente, que é um dos resultados possíveis quando as coisas não estão bem definidos.O token PART1PART2
seguido por *
não serão consideradas para expansão de macro novamente.Stringfication, em seguida, produz o resultado você vê.
Meu gcc se comporta de forma diferente em suas exemplos:
/usr/bin/gcc -O0 -g -std=c89 -pedantic -E test-prepro.c
test-prepro.c:16:1: error: pasting "PART1PART2" and "*" does not give a valid preprocessing token
"works*"
Então, para resumir o caso 1 tem dois problemas.
- Colar dois tokens que não resultam válido de pré-processamento do token.
- ordem de avaliação dos
##
operador de
No caso 3, o seu compilador é dar o resultado errado.Ele deve
- avaliar os argumentos para
STRINGAFY1
- para fazer o que ele tem para expandir
GLUE
GLUE
resultadosPART1PART2*
- o que deve ser expandido novamente
- o resultado é
works*
- o que então é passado para
STRINGAFY1
Outras dicas
Ele está fazendo exatamente o que você está dizendo a ele para fazer.A primeira e a segunda tirar os nomes de símbolo transmitido e colá-los juntos em um novo símbolo.A terceira leva de 2 símbolos e cola-los, então você está colocando o * na seqüência de si mesmo (o que, eventualmente, irá avaliar em outra coisa).
O que é exatamente a questão com os resultados?O que você espera obter?Tudo parece estar funcionando como seria de esperar-la.
Então, naturalmente, a questão de por que você está jogando com as artes das trevas de símbolo adulterar como este de qualquer maneira?:)