Przeczytałem książkę Dennisa Ritchiego The C Programming Language, której int
należy użyć, aby zmienna mogła przechowywać EOF - aby była wystarczająco duża, aby mogła przechowywać wartość EOF - nie char
. Ale następujący kod działa dobrze:
#include<stdio.h>
main() {
char c;
c=getchar();
while(c!=EOF) {
putchar(c);
c=getchar();
}
}
Gdy nie ma już danych wejściowych, getchar
zwraca EOF. W powyższym programie zmienna c
typu char jest w stanie ją z powodzeniem zatrzymać.
Dlaczego to działa? Zgodnie z wyjaśnieniem w powyższej książce kod nie powinien działać.
0xff
. Przechowywanie wynikgetchar()
wint
rozwiązuje tego problemu. Twoje pytanie jest zasadniczo takie samo, jak pytanie 12.1 w często zadawanych pytaniach na temat comp.lang.c , które jest doskonałym źródłem informacji. (Równieżmain()
powinno byćint main(void)
i nie zaszkodzi dodaćreturn 0;
przed zamknięciem}
.)Odpowiedzi:
Twój kod wydaje się działać, ponieważ przypadkowe konwersje typów przypadkowo robią to, co należy.
getchar()
zwraca anint
z wartością, która albo pasuje do zakresu,unsigned char
albo jestEOF
(co musi być ujemne, zwykle wynosi -1). Zauważ, żeEOF
sam nie jest postacią, ale sygnałem, że nie ma już dostępnych znaków.Podczas przechowywania wynik z
getchar()
INc
, istnieją dwie możliwości. Albo typchar
może reprezentować wartość, w którym to przypadku jest to wartośćc
. Lub typchar
nie może reprezentować wartości. W takim przypadku nie jest określone, co się stanie. Procesory Intela po prostu odcinają wysokie bity, które nie pasują do nowego typu (skutecznie zmniejszając wartość modulo 256 dlachar
), ale nie powinieneś na tym polegać.Następnym krokiem jest porównanie
c
zEOF
. JakEOF
jestint
,c
zostanie przekonwertowany naint
również, zachowując wartość przechowywaną wc
. Jeślic
można zapisać wartośćEOF
, wówczas porównanie się powiedzie, ale jeśli niec
można zapisać wartości, porównanie się nie powiedzie, ponieważ nastąpiła nieodwracalna utrata informacji podczas konwersji na typ .EOF
char
Wygląda na to, że Twój kompilator zdecydował się na
char
podpisanie typu, a wartość naEOF
tyle mała, aby zmieściła sięchar
. Gdybychar
były niepodpisane (lub gdybyś użyłunsigned char
), test nie powiódłby się, ponieważunsigned char
nie można utrzymać wartościEOF
.Pamiętaj również, że jest drugi problem z twoim kodem. Ponieważ
EOF
nie jest postacią samą w sobie, ale wymusza się na niejchar
typ, istnieje bardzo prawdopodobieństwo, że zostanie źle zinterpretowana jako istota,EOF
a dla połowy możliwych znaków nie jest zdefiniowane, czy zostaną poprawnie przetworzone.źródło
char
wartości spoza zakresuCHAR_MIN
..CHAR_MAX
będą wymagane jest albo uzyskując wartość implementacji określone, otrzymując wzór bitowy które definiuje realizacji jako reprezentacji pułapki lub spowodować sygnał realizacji określone. W większości przypadków implementacje musiałyby zostać poddane dodatkowej pracy, aby zrobić coś innego niż redukcja dwóch uzupełnień. Jeśli ludzie w Komitecie ds. Standardów popierają pomysł, że należy zachęcać kompilatory do wdrażania zachowań zgodnych z zachowaniem większości innych kompilatorów, jeśli nie ma powodów, aby robić inaczej ...(signed char)x
należy to uznać za jaśniejsze i tak bezpieczne jak((unsigned char)x ^ CHAR_MAX+1))-(CHAR_MAX+1)
.) W tej chwili nie widzę żadnego prawdopodobieństwa kompilatory wdrażające wszelkie inne zachowania zgodne z dzisiejszą normą; jedynym niebezpieczeństwem byłoby to, że Standard mógłby zostać zmieniony, aby przerwać zachowanie w domniemanym interesie „optymalizacji”.int i=129; signed char c=i;
jest jednym z takich zachowań. Stosunkowo niewiele procesorów ma instrukcję, która byłabyc
równa,i
gdy byłaby w zakresie od -127 do +127 i dawałaby dowolne spójne odwzorowanie innych wartościi
na wartości z zakresu od -128 do +127, które różniłyby się od redukcji uzupełnienia dwóch, lub. ..