Uložení znaku EOF (End of File) do typu char
On 18 února, 2021 by admin Četl jsem v C Programovacím jazyce C Dennisa Ritchieho kniha, kterou int
je třeba použít pro proměnnou k uložení EOF –, aby byla dostatečně velká, aby mohla obsahovat hodnotu EOF – ne char
. Následující kód však funguje dobře:
#include<stdio.h> main() { char c; c=getchar(); while(c!=EOF) { putchar(c); c=getchar(); } }
Když existuje již není žádný vstup, getchar
vrací EOF. A ve výše uvedeném programu je proměnná c
s typem char schopna jej udržet úspěšně.
Proč to funguje? Podle vysvětlení ve výše uvedené knize by kód neměl fungovat.
Komentáře
Odpověď
Zdá se, že váš kód funguje, protože převody implicitního typu náhodou způsobí správnou věc.
getchar()
vrací int
s hodnotou, která odpovídá rozsahu unsigned char
nebo je EOF
( což musí být záporné, obvykle je to -1). Všimněte si, že EOF
sám o sobě není znak, ale signál, že již nejsou k dispozici žádné znaky.
Při ukládání výsledku z getchar()
v c
existují dvě možnosti. Hodnotu může představovat buď typ char
, v takovém případě se jedná o hodnotu c
. Nebo typ char
nemůže představovat hodnotu. V takovém případě není definováno, co se stane. Procesory Intel jen usekají vysoké bity, které se do nového typu nehodí (čímž se efektivně snižuje hodnota modulo 256 pro char
), ale na to byste se neměli spoléhat.
Dalším krokem je porovnání c
s EOF
. Jak EOF
je int
, c
bude také převeden na int
, přičemž zachová uloženou hodnotu v c
. Pokud c
může uložit hodnotu EOF
, bude srovnání úspěšné , ale pokud c
nemohl ne uložit hodnotu, pak srovnání selže, protože při převodu zadat char
.
Zdá se, že se váš kompilátor rozhodl vytvořit typ char
podepsané a hodnota EOF
malá dost na to, aby se vešlo char
. Pokud char
nebyly podepsány (nebo pokud jste použili unsigned char
), váš test by selhal, protože unsigned char
nemůže „udržet hodnotu EOF
.
Upozorňujeme, že s vaším kódem existuje druhý problém. Jako EOF
není samotná postava, ale vložíte ji do char
typu, je velmi pravděpodobné, že tam bude postava, která bude chybně interpretována jako EOF
a u poloviny možných znaků není definováno, zda budou správně zpracovány.
Komentáře
- Vynucování k napsání
char
hodnot mimo rozsahCHAR_MIN
..CHAR_MAX
bude vyžadován buď výtěžek hodnotu definovanou implementací, dát bitový vzor, který implementace definuje jako reprezentaci depeše, nebo vyvolat signál definovaný implementací. Ve většině případů by implementace musely projít spoustou práce navíc a dělat cokoli jiného než dvě ' redukce s-komplementu.Pokud by se lidé ve výboru pro standardy přihlásili k myšlence, že kompilátoři by měli být povzbuzováni k implementaci chování konzistentního s chováním většiny ostatních kompilátorů, pokud neexistují důvody pro opak … - … považoval bych takové nátlak jako spolehlivý (nemluvě o tom, že by kód neměl ' dokumentovat jeho záměry, ale
(signed char)x
by měl být považován za jasnější a stejně bezpečné jako((unsigned char)x ^ CHAR_MAX+1))-(CHAR_MAX+1)
.) Jak to je, nevidím žádnou pravděpodobnost, že kompilátoři implementují jakékoli jiné chování vyhovující dnešní ' s standard; jediným nebezpečím by bylo, že by standard mohl být změněn tak, aby narušil chování v předpokládaném zájmu " optimalizace ". - @supercat: Standard je napsán tak, že žádný kompilátor nemusí vytvářet kód, který má chování, které přirozeně nepodporuje procesor, na který cílí. Většina nedefinovaného chování existuje, protože (v době psaní normy) se ne všechny procesory chovaly konzistentně. S vyspělejšími kompilátory začali autoři překladačů využívat nedefinované chování k vytváření agresivnějších optimalizací.
- Historicky byl záměr standardu většinou takový, jaký popisujete, ačkoli standard popisuje některá chování v dostatečné podrobnosti, aby vyžadovaly, aby překladače pro některé běžné platformy generovaly více kódu, než by bylo požadováno podle specifikace volnějšího. Jedním z takových chování je nátlak typu v
int i=129; signed char c=i;
. Relativně málo procesorů má instrukci, která byc
vyrovnalai
, když je ' s rozsah -127 až +127 a přineslo by jakékoli konzistentní mapování dalších hodnoti
na hodnoty v rozsahu -128 až +127, které se lišily od dvou ' S-doplněk redukce, nebo … - … by v takových případech důsledně zvýšil signál. Jelikož standard vyžaduje, aby implementace přinesly konzistentní mapování nebo důsledně zvyšovaly signál, jedinou platformou, kde by standard ponechal prostor pro něco jiného než dvě ' redukce s-komplementu, by byly věci jako DSP se saturačním aritmetickým hardwarem. Pokud jde o historický základ pro nedefinované chování, řekl bych, že problém není ' t pouze s hardwarovými platformami. I na platformě, kde by se overflow choval velmi konzistentně, může být užitečné mít kompilátor v pasti …
0xff
. Ukládání výsledkugetchar()
vint
tento problém řeší. Vaše otázka je v zásadě stejná jako otázka 12.1 v comp.lang.c FAQ , což je vynikající zdroj. (Takémain()
by mělo býtint main(void)
a ' by neuškodilo přidatreturn 0;
před závěrečným}
.)