C. FÜGGELÉK:
A C nyelv szabvány bevezetéséből adódó változásai
A könyv első kiadása óta a C nyelv definíciója nagy változásokon ment keresztül. Majdnem minden változás az eredeti nyelv kiterjesztése volt, és a gondos tervezés következtében az új definíció szerinti C nyelv a meglévő gyakorlati alkalmazásokkal kompatibilis maradt. Az eredeti leírás néhány nem egyértelmű megfogalmazását kijavították és néhány módosítást vezettek be a meglévő gyakorlatnak megfelelően. Sok bejelentett új lehetőség az AT&T rendelkezésre álló fordítóprogramjának velejárója volt, és ezt követően adaptálták más C fordítókba. Ezekután az ANSI megfelelő bizottsága ezeket a változásokat meghagyva szabványosította a nyelvet és további jelentős módosításokat is bevezetett. A szabványban foglaltakat előre látva, még annak megjelenése előtt néhány fordítóprogram is megjelent a piacon.
Ez a függelék összefoglalja a könyv első kiadásában és a szabványban definiált C nyelvek közötti különbségeket. Itt csak a nyelvvel magával foglalkozunk, a környezettel (operációs rendszerrel) és a könyvtárral nem. Ez utóbbiak ugyan fontos részét alkotják a szabványnak, de az itteni változások ismertetésének nincs jelentősége, mivel ezekkel a könyv első kiadásában nem foglalkoztunk.
- A Szabvány az előfeldolgozó rendszert sokkal gondosabban definiálta, mint a könyv első kiadása. Az előfeldolgozó rendszer explicit módon a szintaktikai egységekre (tokenekre) bontáson alapszik; új operátorok lettek bevezetve a tokenek láncba fűzésére (##) és karaktersorozatok létrehozására (#); új vezérlősorok lettek bevezetve (#elif, #pragma); explicit módon megengedetté vált a makrók azonos token-sorozattal való újradeklarálása; a karaktersorozat belsejében lévő paramétereket a rendszer a továbbiakban már nem helyettesíti. Az előfeldolgozónak szóló sorok \ jellel való tördelése mindenhol megengedett, nem csak a karaktersorozatokban vagy a makródefíníciókban. (A részleteket l. az A12. pontban.)
- Az összes belső azonosító nevének szignifikanciája 31 karakterre növekedett; a külső csatolással rendelkező azonosítók nevének szignifikanciájára adott alsó határ megmaradt 6, csak kis- vagy csak nagybetűs karakter. (Számos gépi megvalósítás több karaktert is megenged.)
- A ?? kezdetű trigráf sorozatok bevezetése lehetővé tette a karakterkészletek egy részéből hiányzó karakterek (# \ ^ [ ] { } | ~) ábrázolását (l. az A12. pontot). Ügyeljünk rá, hogy a trigráf sorozatok bevezetése változást okozhat a ?? karaktereket tartalmazó karaktersorozatok jelentésében.
- Új kulcsszavakat (void, const, volatile, signed, enum) vezettek be, a sikertelen kísérletet jelentő entry kulcsszót viszont törölték a szabványból.
- A karaktersorozatokban és karaktersorozat-állandókban használható új escape-sorozatokat definiáltak. A \ utáni, a megadott escape-sorozatok között nem szereplő karakterek hatását nem definiálták (l. az A2.5.2. pontot).
- Mindenki számára kedvező, triviális változás, hogy a 8 és 9 nem oktális számjegy.
- A Szabvány az állandók típusának explicit kijelölésére utótagokat vezetett be: az U és L az egészek, F és L a lebegőpontos állandók esetén használható. Az utótag nélküli állandók típusára vonatkozó szabályok szintén finomodtak (l. az A2.5. pontot).
- A szomszédos karaktersorozat-állandók összefűződnek (konkatenálódnak).
- A Szabvány lehetővé teszi a széles karakterekből álló karakteres és karaktersorozatállandók használatát (l. A2.6.).
- A karakterek, csakúgy mint más egész adattípusok is, explicit módon deklarálhatók előjeles vagy előjel nélküli számábrázolással. Ez a signed vagy unsigned kulcsszóval valósítható meg. A double adattípus szinonimájaként használt long float típusjelzést a Szabvány megszüntette, de bevezette a long double típust, amellyel extra pontosságú lebegőpontos adatok deklarálhatók.
- Korábban csak az unsigned char típus létezett. A Szabvány bevezette a signed kulcsszót, amivel a char és más egész típusok explicit módon előjelessé tehetők.
- A void típus számos gépi megvalósításban évek óta létezett. A Szabvány bevezette a void * típust, mint generikus (általános) mutató típust. Ezt a szerepet korábban a char * töltötte be. Ugyanakkor explicit szabályokat hoztak a mutatók és az egészek, ill. a különböző típusú mutatók kényszerített típuskonverzió nélküli keveredésének megakadályozására.
- A Szabvány tételesen megadja az aritmetikai adattípusok minimális nagyságát és a megfelelő headerek (<limits.h> és <float.h>) tartalmazzák az egyes gépi megvalósítások adattípusokra vonatkozó előírásait.
- A felsorolások alkalmazása új a könyv első kiadásához képest.
- A Szabvány a C++ nyelvből átvette a típusminősítő fogalmát, pl. a const típusminősítőt (l. az A8.2. pontot).
- A Szabvány szerinti C nyelvben a karaktersorozatok már nem módosíthatók, így csak olvasható tárolóban is elhelyezhetők.
- A könyv első kiadásában alkalmazott „szokásos aritmetikai konverziók" szabálya megváltozott, különösen alapvető a változás, hogy az „egészek esetén mindig az unsigned típusnak, lebegőpontos adatok esetén pedig a double típusnak van elsősége", valamint a „legkisebb, elegendően nagy típusra való előlépés" szabály módosult (l. az A6.5. pontot).
- A régi értékadó operátorok, mint pl. az =+, eltűntek a Szabványból. Változás még, hogy az értékadó operátorok egyetlen szintaktikai egységet alkotnak, szemben a könyv első kiadásával, ahol üres hellyel elválasztott párt alkottak.
- A fordítóprogramok korábban megengedték a matematikailag asszociatív operátorok számítási szempontból asszociatív kezelését. Ez a szabály a Szabvány bevezetésével megszűnt.
- A Szabvány az unáris - operátor mintájára, szimmetria okokból bevezette az unáris + operátort.
- Egy függvényhez tartozó mutató az explicit * operátor nélkül használható függvény-megnevezésként (l. az A7.3.2. pontot).
- A struktúrák szerepelhetnek értékadásban, átadhatók függvénynek paraméterként és lehetnek függvény visszatérési értékei.
- Az & címoperátor alkalmazása tömbökre is megengedett és az eredménye a tömböt címző mutató.
- A könyv első kiadásában a sizeof operátor int típusú eredményt adott, ami számos gépi megvalósításban unsigned minősítésű volt. A Szabvány a sizeof eredményének típusát gépi megvalósítástól függővé tette, és ehhez bevezetett egy speciális, size_t adattípust, ami az <stddef.h> standard headerben van definiálva. Hasonló módon kezeli a Szabvány a mutatók különbségének típusát, amelyhez a ptrdiff_t adattípus lett bevezetve (l. az A7.4.8. és A7.7. pontokat).
- Az & címoperátor nem alkalmazható register tárolási osztályúnak deklarált objektumokra, még akkor sem, ha a gépi megvalósítás szerint az objektum nem regiszterben tárolódik.
- A léptető kifejezések típusa a bal oldali operandus típusának felel meg, a jobb oldali operandus nem lép elő az eredmény típusának megfelelően (l. az A7.8. pontot).
- A Szabvány megengedi egy tömb utolsó utáni elemét címző mutató létrehozását és annak aritmetikai, ill. relációs kifejezésekben való szerepeltetését (l. az A7.7. pontot).
- A Szabvány – a C++ nyelvből átvéve – bevezette a függvényprototípus deklarációt, ami a paraméterek típusát is tartalmazza, valamint a változó hosszúságú paraméterlista explicit jelölési módját, egyben megadva annak feldolgozási lehetőségét is (l. az A7.3.2., A8.6.3. és B7. pontokat). A régi stílusú függvénydeklaráció továbbra is érvényben maradt, de megszorításokkal.
- Az üres deklarációkat, amelyekben nincs deklarátor és nem deklarálnak legalább egy struktúrát, uniont vagy felsorolást, a Szabvány tiltja. Másrészről egy struktúra vagy union címkéjét újra deklaráló deklaráció megengedett, ha az újra deklarálás egy külső érvényességi tartományban történik.
- A valamilyen specifikátort vagy minősítőt nem tartalmazó külső adatdeklarációk (vagyis a puszta deklarátorból álló deklaráció) alkalmazása tilos.
- Néhány gépi megvalósításban a belső blokkban található extern deklaráció érvényességi tartománya kiterjedt a forrásállomány további részére is. A Szabvány világosan rögzíti, hogy az ilyen deklarációk érvényességi tartománya csak az a blokk, amelyben szerepelnek.
- A paraméterek érvényességi tartománya a függvényt alkotó összetett utasítás, így a függvény törzsének tetején lévő változódeklarációk nem rejthetik el a paramétereket.
- Az azonosítók névterekbe osztása a könyv első kiadásában szereplő felosztáshoz képest megváltozott. A Szabvány a struktúrák, unionok és felsorolások címkéit egyetlen névtérbe helyezi, és bevezet egy önálló névteret az utasításcímkék számára (l. az A11.1. pontot). A struktúra- vagy uniontagok nevei annak a struktúrának vagy unionnak a névteréhez kapcsolódnak, amelynek részét alkotják. (Ez megfelel a régóta fennálló gyakorlatnak.)
- Az unionok inicializálhatók, a kezdeti értéket az union első tagjához rendelik.
- Az automatikus struktúrák, unionok és tömbök inicializálhatók, bár van néhány megkötés.
- Az explicit módon megadott méretű karakteres tömbök pontosan ugyanannyi karaktert tartalmazó karaktersorozat-állandóval inicializálhatók (ilyenkor a '\0' végjelet egyszerűen kilépteti a rendszer).
- A switch utasítás vezérlő kifejezése és case címkéje bármilyen egész típusú lehet.