Estou lendo um código de emulador e rebati algo realmente estranho:
switch (reg){
case 'eax':
/* and so on*/
}
Como isso é possível? Achei que você pudesse apenas switch
nos tipos integrais. Existe algum truque macro acontecendo?
c
switch-statement
label
constants
Ian Colton
fonte
fonte
'eax'
e enumera o valor inteiro constanteint
, então é legal. No entanto, o valor de uma constante de vários caracteres é definido pela implementação, portanto, o código pode não funcionar como esperado em outro compilador. Por exemplo,eax
pode ser0x65
,0x656178
,0x65617800
,0x786165
,0x6165
, ou qualquer outra coisa.'eax' != 'ebx'
, é claro, falhe apenas um ou dois de seus exemplos. Embora possa haver algum código em algum lugar que, de fato*(int*)("eax") == 'eax'
, assume e, portanto, falha na maioria dos seus exemplos.'eax'
pode comparar igual a'ebx'
ou a'ax'
, e a instrução switch não funcionaria conforme o esperado.Respostas:
(Só você pode responder à parte dos "truques de macro" - a menos que cole mais código. Mas não há muito aqui para as macros trabalharem - formalmente, você não tem permissão para redefinir palavras-chave ; o comportamento ao fazer isso é indefinido.)
Para conseguir a legibilidade do programa, o desenvolvedor inteligente está explorando o comportamento definido pela implementação . não
'eax'
é uma string, mas uma constante de vários caracteres . Observe com muito cuidado os caracteres de aspas simples ao redor . Provavelmente, está dando a você um, no seu caso, que é exclusivo para essa combinação de personagens. (Freqüentemente, cada caractere ocupa 8 bits em um 32 bits ). E todo mundo sabe que você pode em umeax
int
int
switch
int
!Finalmente, uma referência padrão:
O padrão C99 diz:
fonte
'ab'
partir'a'
e'b'
.De acordo com o padrão C (6.8.4.2 A declaração switch)
e (6.6 Expressões constantes)
Agora o que é
'eax'
?O padrão C (6.4.4.4 constantes de caracteres)
Então,
'eax'
é uma constante de caractere inteiro de acordo com o parágrafo 10 da mesma seçãoPortanto, de acordo com a primeira citação mencionada, pode ser um operando de uma expressão de constante inteira que pode ser usada como um rótulo de caso.
Observe que uma constante de caractere (entre aspas simples) tem tipo
int
e não é o mesmo que uma string literal (uma sequência de caracteres entre aspas duplas) que tem um tipo de matriz de caracteres.fonte
Como já foi dito, este é um
int
constante e seu valor real é definido pela implementação.Presumo que o resto do código se pareça com
Você pode ter certeza de que 'eax' na primeira parte tem o mesmo valor que 'eax' na segunda parte, então tudo deu certo, certo? ... errado.
Em um comentário, @Davislor lista alguns valores possíveis para 'eax':
Observe o primeiro valor potencial? Isso mesmo
'e'
, ignorando os outros dois personagens. O problema é o programa provavelmente usa'eax'
,'ebx'
e assim por diante. Se todas essas constantes tiverem o mesmo valor que'e'
você acaba comIsso não parece muito bom, não é?
A parte boa sobre "definido por implementação" é que o programador pode verificar a documentação de seu compilador e ver se ele faz algo sensato com essas constantes. Se isso acontecer, fique em casa gratuitamente.
A parte ruim é que algum outro pobre sujeito pode pegar o código e tentar compilá-lo usando algum outro compilador. Erro de compilação instantânea. O programa não é portátil.
Como @zwol apontou nos comentários, a situação não é tão ruim quanto eu pensava, no caso de o código não compilar. Isso fornecerá pelo menos um nome de arquivo exato e um número de linha para o problema. Mesmo assim, você não terá um programa funcionando.
fonte
assert('eax' != 'ebx'); //if this fails you can't compile the code because...
há algo que o autor original poderia fazer para evitar outras falhas do compilador sem substituir a construção inteiramente>O fragmento de código usa uma estranheza histórica chamada constante de caractere multi-caracteres , também conhecida como multi-chars .
'eax'
é uma constante inteira cujo valor é definido pela implementação.Aqui está uma página interessante sobre vários caracteres e como eles podem ser usados, mas não devem:
http://www.zipcon.net/~swhite/docs/computers/languages/c_multi-char_const.html
Olhando mais para trás no espelho retrovisor, aqui está como o manual C original de Dennis Ritchie dos bons velhos tempos ( https://www.bell-labs.com/usr/dmr/www/cman.pdf ) especificava constantes de caracteres .
A última frase é tudo que você precisa lembrar sobre esta construção curiosa: constantes de caractere com mais de um caractere são inerentemente dependentes da máquina e devem ser evitadas.
fonte