Lagring av EOF (End of File) -tegnet i en type char
On februar 18, 2021 by admin Jeg leste i Dennis Ritchies s The C Programming Language bok som int
må brukes for at en variabel skal ha EOF – for å gjøre den tilstrekkelig stor slik at den kan holde EOF-verdien – ikke char
. Men følgende kode fungerer bra:
#include<stdio.h> main() { char c; c=getchar(); while(c!=EOF) { putchar(c); c=getchar(); } }
Når det er er ikke mer inngang, getchar
returnerer EOF. Og i ovennevnte program er variabelen c
i stand til å holde den vellykket.
Hvorfor fungerer dette? I følge forklaringen i boken ovenfor skal koden ikke fungere.
Kommentarer
Svar
Koden din ser ut til å fungere, fordi de implisitte konverteringene tilfeldigvis gjør det rette.
getchar()
returnerer en int
med en verdi som enten passer til området unsigned char
eller er EOF
( som må være negativ, vanligvis er det -1). Merk at EOF
i seg selv ikke er et tegn, men et signal om at det ikke er flere tegn tilgjengelig.
Når du lagrer resultatet fra getchar()
i c
er det to muligheter. Enten kan typen char
representere verdien, i så fall er det verdien til c
. Eller typen char
kan ikke representerer verdien. I så fall er det ikke definert hva som vil skje. Intel-prosessorer hogger bare av de høye bitene som ikke passer inn i den nye typen (effektivt reduserer verdien modulo 256 for char
), men du bør ikke stole på det.
Det neste trinnet er å sammenligne c
med EOF
. Som EOF
er en int
, c
blir også konvertert til en int
, og lagrer verdien i c
. Hvis c
kunne lagre verdien av EOF
, vil sammenligningen lykkes , men hvis c
ikke kunne ikke lagre verdien, vil sammenligningen mislykkes, fordi det har vært et uopprettelig tap av informasjon under konvertering av EOF
for å skrive char
.
Det ser ut til at kompilatoren din valgte å lage char
signert og verdien av EOF
liten nok til å passe inn char
. Hvis char
ikke var signert (eller hvis du hadde brukt unsigned char
), ville testen din mislyktes, fordi unsigned char
kan ikke holde verdien til EOF
.
Vær også oppmerksom på at det er et annet problem med koden din. Som EOF
er ikke et tegn i seg selv, men du tvinger det til en char
-type, det er veldig sannsynlig et tegn der ute som blir mistolket som EOF
og for halvparten av de mulige tegnene er det udefinert om de vil bli behandlet riktig.
Kommentarer
- Tvang for å skrive
char
verdier utenfor områdetCHAR_MIN
..CHAR_MAX
vil kreves for å enten gi en implementeringsdefinert verdi, gi et bitmønster som implementeringen definerer som en fellerepresentasjon, eller heve et implementeringsdefinert signal. I de fleste tilfeller må implementeringer gå gjennom mye ekstra arbeid for å gjøre noe annet enn to ' s-komplementreduksjon.Hvis folk i standardkomiteen abonnerer på ideen om at kompilatorer skal oppfordres til å implementere atferd som er i samsvar med de fleste andre kompilatørers i mangel av grunner til å gjøre noe annet … - … Jeg vil anse slik tvang som pålitelig (for ikke å si at koden ikke skal ' t dokumentere sine intensjoner, men at
(signed char)x
er, bør betraktes som klarere og like trygt som((unsigned char)x ^ CHAR_MAX+1))-(CHAR_MAX+1)
.) Som det er, ser jeg ikke ' ikke sannsynligheten for at kompilatorer implementerer annen oppførsel som er i samsvar med i dag ' s standard; den ene faren vil være at standarden kan endres for å bryte oppførselen i den antatte interessen til " optimalisering ". - @ supercat: Standarden er skrevet slik at ingen kompilator trenger å produsere kode som har atferd som ikke naturlig støttes av prosessoren den målretter mot. Det meste av den udefinerte oppførselen er der fordi (i skrivende stund) ikke alle prosessorer oppførte seg konsekvent. Med at kompilatorene blir mer modne, har kompilatorforfattere begynt å utnytte den udefinerte oppførselen for å gjøre mer aggressive optimaliseringer.
- Historisk var intensjonen med standarden stort sett som du beskriver, selv om standarden beskriver noen atferd i tilstrekkelig detalj for å kreve kompilatorer for at noen vanlige plattformer skal generere mer kode enn det som kreves under en løsere spesifikasjon. Typen tvang i
int i=129; signed char c=i;
er en slik oppførsel. Relativt få prosessorer har en instruksjon som vil gjørec
liki
når den ' er i området -127 til +127 og vil gi en jevn kartlegging av andre verdier avi
til verdier i området -128 til +127 som skilte seg fra to ' s-komplementreduksjon, eller … - … vil konsekvent heve et signal i slike tilfeller. Siden standarden krever at implementeringer enten gir en jevn kartlegging eller konsekvent hever et signal, vil de eneste plattformene der standarden gir rom for noe annet enn to ' s-komplementreduksjon være ting som DSP-er med metning-aritmetisk maskinvare. Når det gjelder det historiske grunnlaget for udefinert oppførsel, vil jeg si at problemet ikke er ' t bare med maskinvareplattformer. Selv på en plattform der overløp vil oppføre seg på en veldig konsistent måte, kan det være nyttig å ha en kompilator som feller den …
0xff
. Lagrer resultatet avgetchar()
i enint
løser det problemet. Spørsmålet ditt er egentlig det samme som spørsmål 12.1 i comp.lang.c FAQ , som er en utmerket ressurs. (Også,main()
skal væreint main(void)
, og det ville ikke være ' å skadereturn 0;
før den avsluttende}
.)