Czytam kod emulatora i odpowiedziałem na coś naprawdę dziwnego:
switch (reg){
case 'eax':
/* and so on*/
}
Jak to jest możliwe? Myślałem, że możesz tylko switch
na typach całkowitych. Czy ma miejsce jakieś sztuczki makro?
c
switch-statement
label
constants
Ian Colton
źródło
źródło
'eax'
i wylicza stałą wartość całkowitąint
, więc jest to legalne. Jednak wartość stałej wieloznakowej jest zdefiniowana w ramach implementacji, więc kod może nie działać zgodnie z oczekiwaniami na innym kompilatorze. Na przykład,eax
może być0x65
,0x656178
,0x65617800
,0x786165
,0x6165
, lub coś innego.'eax' != 'ebx'
Oczywiście pod warunkiem , że zawodzi tylko jeden lub dwa z twoich przykładów. Chociaż może być gdzieś jakiś kod, który w efekcie zakłada*(int*)("eax") == 'eax'
, a zatem zawodzi większość twoich przykładów.'eax'
może porównać równa się'ebx'
lub do'ax'
, a instrukcja switch nie zadziała zgodnie z zamierzeniami.Odpowiedzi:
(Tylko Ty możesz odpowiedzieć na część „sztuczki makr” - chyba że wkleisz więcej kodu. Ale nie ma tu zbyt wiele do pracy z makrami - formalnie nie możesz przedefiniować słów kluczowych ; zachowanie przy robieniu tego jest niezdefiniowane).
Aby uzyskać czytelność programu, dowcipny programista wykorzystuje określone w implementacji zachowanie .
'eax'
to nie łańcuch, ale stała wieloznakowy . Zwróć szczególną uwagę na pojedyncze cudzysłowyeax
. Najprawdopodobniej daje ci toint
w twoim przypadku unikalne dla tej kombinacji postaci. (Dość często każdy znak zajmuje 8 bitów w 32-bitowymint
). I każdy wie, że możeswitch
na zasadzieint
!Na koniec standardowe odniesienie:
Standard C99 mówi:
źródło
'ab'
from'a'
i'b'
.Zgodnie ze standardem C (6.8.4.2 Instrukcja dotycząca przełącznika)
i (6.6 Wyrażenia stałe)
Co teraz jest
'eax'
?Standard C (6.4.4.4 Stałe znakowe)
Więc
'eax'
jest stałą znakową liczbą całkowitą zgodnie z paragrafem 10 tej samej sekcjiZatem zgodnie z pierwszym cytatem może to być operand wyrażenia będącego liczbą całkowitą, która może być używana jako etykieta przypadku.
Zwróć uwagę, że stała znakowa (ujęta w pojedyncze cudzysłowy) ma typ
int
i nie jest tym samym, co literał łańcuchowy (sekwencja znaków ujęta w podwójne cudzysłowy), która ma typ tablicy znaków.źródło
Jak powiedzieli inni, jest to
int
stała, a jej rzeczywista wartość jest określona przez implementację.Zakładam, że reszta kodu wygląda mniej więcej tak
Możesz być pewien, że „eax” w pierwszej części ma taką samą wartość jak „eax” w drugiej części, więc wszystko działa, prawda? ... źle.
W komentarzu @Davislor wymienia kilka możliwych wartości dla „eax”:
Zwróć uwagę na pierwszą potencjalną wartość? To po prostu
'e'
ignorowanie pozostałych dwóch znaków. Problemem jest program prawdopodobnie używa'eax'
,'ebx'
i tak dalej. Jeśli wszystkie te stałe mają taką samą wartość,'e'
jaką otrzymujeszTo nie wygląda zbyt dobrze, prawda?
Zaletą „definicji implementacji” jest to, że programista może sprawdzić dokumentację swojego kompilatora i zobaczyć, czy robi coś sensownego z tymi stałymi. Jeśli tak, dom za darmo.
Złe jest to, że jakiś inny biedak może wziąć kod i spróbować skompilować go przy użyciu innego kompilatora. Natychmiastowy błąd kompilacji. Program nie jest przenośny.
Jak @zwol zauważył w komentarzach, sytuacja nie jest tak zła, jak myślałem, w złym przypadku kod się nie kompiluje. To przynajmniej poda dokładną nazwę pliku i numer wiersza dla problemu. Mimo to nie będziesz miał działającego programu.
źródło
assert('eax' != 'ebx'); //if this fails you can't compile the code because...
jest coś, co pierwotny autor mógłby zrobić, aby zapobiec innym awariom kompilatora bez całkowitego zastąpienia konstrukcji>Fragment kodu wykorzystuje historyczną osobliwość zwaną wieloznakową stałą znakową, nazywaną również wieloznakową .
'eax'
jest stałą całkowitą, której wartość jest zdefiniowana w implementacji.Oto interesująca strona na temat wielu znaków i tego, jak można ich używać, ale nie powinno:
http://www.zipcon.net/~swhite/docs/computers/languages/c_multi-char_const.html
Patrząc dalej w lusterko wsteczne, oto jak oryginalny podręcznik C autorstwa Dennisa Ritchiego z dawnych dobrych czasów ( https://www.bell-labs.com/usr/dmr/www/cman.pdf ) określał stałe znakowe .
Ostatnia fraza to wszystko, co musisz pamiętać o tej dziwnej konstrukcji: Stałe znakowe z więcej niż jednym znakiem są z natury zależne od maszyny i należy ich unikać.
źródło