Sedm kohout∙ na smetiÜti, jeÜt∞ jednou

 

V tomto Φlßnku se vracφme k porovnßvßnφ n∞kter²ch b∞₧n∞ dostupn²ch p°ekladaΦ∙ jazyka C++. Na rozdφl od Φlßnku Sedm kohout∙ na smetiÜti z tohoto Φφsla tiÜt∞nΘho Chipu zde najdete nejen vφce technick²ch podrobnostφ, ale takΘ ukßzky zdrojovΘho k≤du.

Uve∩me si nejprve porovnßvanΘ p°ekladaΦe znovu spolu se spolu se zkratkami, pomocφ nich₧ se na n∞ budeme v dalÜφm textu odvolßvat. Jde o

P°ekladaΦe jsou zde se°azeny v abecednφm po°adφ a toto po°adφ nevyjad°uje ₧ßdnΘ hodnocenφ. Zßkladnφ fakta o nich jsme ji₧ uvedli v Φlßnku Sedm kohout∙ na smetiÜti. Zde najdete nejen podrobn∞jÜφ porovnßnφ zahrnujφcφ v∞tÜφ poΦet kritΘriφ, ale i ukßzky zdrojovΘho k≤du.

KritΘria

Pro porovnßvßnφ jsme se rozhodli pou₧φt nßsledujφcφ kritΘria:

Jazyk C

V Φlßnku Sedm kohout∙ na smetiÜti v tiÜt∞nΘm Chipu jsme zkoumali, zda p°ekladaΦe implementujφ nßsledujφcφ konstrukce po₧adovanΘ standardem [1]:

K nim p°idßme jeÜt∞ nßsledujφcφ:

Tabulka 1 obsahuje v²sledky pro vÜechny porovnßvanΘ p°ekladaΦe.

  BC6 BCX BCXP GNU INT71 VC02 VC03 ISO
Typy long long ne ano ano ano ano ano ano 6.2.5.
Identifikßtor __func__ ne ne ano ano ano ne ne 6.4.2.2
Reßlnß Φ. hexadecimßln∞ ne ne ne ano ano ne ne 6.4.4.2
Jedno°ßdkov² komentß° ano ano ano ano ano ano ano 6.4.9.
StrukturovΘ literßly ne ne ano ano ano ne ne 6.5.2.5
Modifikßtor restrict ne ne ano ne ano ne ne 6.7.3.
Funkce inline __inline __inline ano ano ano __inline __inline 6.7.4.
Nekonstantnφ meze polφ ne ne ano (ne sizeof, hroutφ se p°ekladaΦ) ano ano ne ne 6.7.5.2
StatickΘ meze polφ ne ne ignoruje ne ignoruje chyba ignoruje 6.7.5.2
Nedeklarovanß fce varovßnφ varovßnφ chyba chyba varovßnφ toleruje toleruje 6.7.5.3
PojmenovanΘ inicializßtory ne ne ano ne ano ne ne 6.7.8.
Deklarace mezi p°φkazy ne ne ano ano ano ne ne 6.8
Implicitnφ int toleruje toleruje varovßnφ chyba varovßnφ toleruje toleruje 6.9.1.
typedef funkce toleruje toleruje chyba chyba chyba chyba chyba 6.9.1.
Makra s v²pustkou ne ne ano ano ano ne ne 6.10.3.
Typy _Complex ne ne ano ano (?) ano (?) ne ne 7.3
hlaviΦka <fenv.h> ne ne ano ano ne ne ne 7.6
Makro va_copy ne ne zhroutφ se p°ekladaΦ ano ne ne ne 7.15.
HlaviΦka <stdbool.> ne ne ano ano ne (typ_Bool ano) ne ne 7.16.
HlaviΦka <stdint.h> ne ano ano ano ne ne ne 7.18.

 

JednotlivΘ polo₧ky v nφ jsou se°azeny podle po°adφ, v jakΘm jsou ve standardu uvedeny.

Poznßmky

Zde projdeme jednotlivΘ body v po°adφ, ve kterΘm jsou uvedeny v tabulce 1. (╚φslo za nadpisem odkazuje na p°φsluÜn² oddφl standardu [1].)

Rysy jazyka C99, kterΘ nejsou zßvislΘ jen na hlaviΦkov²ch souborech, jsou v BCXP dostupnΘ pouze p°i p°ekladu s nastaven²m p°epφnaΦem ûC99; v INT71 je t°eba pou₧φt p°epφnaΦe /Qc99 a Qrestrict.

Je takΘ t°eba p°ipomenout, ₧e p°ekladaΦ INT71 vyu₧φvß hlaviΦkovΘ soubory n∞kterΘho z p°ekladaΦ∙ firmy Microsoft (podle toho, kde ho instalujeme). My jsme ho instalovali spolu s VC03.

Typy long long a unsigned long long (6.2.5)

VÜechny zkoumanΘ p°ekladaΦe umo₧≥ujφ deklarovat prom∞nnΘ t∞chto typ∙. Umo₧≥ujφ i zapsat literßly s p°φponami LL nebo LLU. Ve vÜech p°φpadech jde o 64bitovß celß Φφsla, kterß se ve starÜφch p°ekladaΦφch objevovala jako rozÜφ°enφ pod oznaΦenφm __int64, resp. unsigned __int64.

Standard ovÜem takΘ zavßdφ specifikace "%lld", resp. "%llu" pro vstup a v²stup t∞chto hodnot pomocφ funkcφ scanf(), printf() a dalÜφch. Äßdn² z porovnßvan²ch p°ekladaΦ∙ ji ale nepodporuje; ve vÜech p°φpadech je t°eba pou₧φt nestandardnφ specifikaci "%I64d", resp. "%I64u", zavedenou p∙vodn∞ jako rozÜφ°enφ pro typy __int64. Pouze p°ekladaΦ BCX p°ipouÜtφ v p°φpad∞ v²stupu takΘ specifikaci "%LLd", kterß ovÜem takΘ postrßdß oporu ve standardu.

Identifikßtor __func__ (6.4.2.2)

V ka₧dΘ funkci by m∞l b²t podle novΘho standardu definovßn identifikßtor

 

static const char __func__[] = "jmΘno_funkce";

 

Jde o pohodln² nßstroj, kter² by m∞lo mj. vyu₧φvat i znßmΘ ladicφ makro assert(). Jak u₧ vφme, z porovnßvan²ch p°ekladaΦ∙ ho implementujφ pouze BCXP, INT71 a GNU; ale GNU a INT71 ho nevyu₧φvß v makru assert(). To znamenß, ₧e pokud aserce neplatφ, pouze BCXP vypφÜe jmΘno funkce, v nφ₧ k chyb∞ doÜlo. 

Hexadecimßlnφ zßpis a v²stup reßln²ch Φφsel

Ve zdrojovΘm textu bychom m∞li mφt mo₧nost zapisovat reßlnß Φφsla v ÜestnßctkovΘ soustav∞ ve tvaru nap°. 0xA23.4AP-12. Zde P oznaΦuje exponentovou Φßst Φφsla, ovÜem vzta₧enou k zßkladu 2, nikoli 10 nebo 16.

Tuto mo₧nost nabφzφ pouze p°ekladaΦ INT71.

Standard takΘ po₧aduje, abychom mohli reßlnß Φφsla v ÜestnßctkovΘm tvaru vypsat, a to pomocφ konverzφ a, resp. A. Tuto mo₧nost ₧ßdn² z p°ekladaΦ∙ neimplementuje.

Jedno°ßdkov² komentß° (6.4.9)

Komentß°e zaΦφnajφcφ dv∞ma lomφtky a konΦφcφ na konci °ßdku se v p°ekladaΦφch jazyka C objevujφ jako rozÜφ°enφ ji₧ velice dlouho, a nikoho nep°ekvapφ, ₧e ho implementujφ vÜechny p°ekladaΦe, o nich₧ zde hovo°φme.

StrukturovΘ literßly (6.5.2.5)

Tato konstrukce z C99 zapl≥uje pom∞rn∞ nepochopitelnou mezeru ve vyjad°ovacφch prost°edcφch starÜφch verzφ jazyka C a v jistΘm smyslu se nahrazuje konstruktory z C++. Umo₧≥uje toti₧ zapsat v programu literßl (p°φmo zapsanou konstantu) p°edstavujφcφ strukturu nebo pole. Podφvejme se na jednoduch² p°φklad, ve kterΘm p°edpoklßdßme, ₧e x je prom∞nnß typu Bubu:

 

struct Bubu {int x;} x;

// ...

x = (struct Bubu){1};          // x je prom∞nnß typu Bubu

int *p = (int[3]){1,2,3};

 

Tuto mo₧nost podporujφ pouze p°ekladaΦe BCPX, INT71 a GNU.

Modifikßtor restrict (6.7.3)

Modifikßtor restrict by m∞lo b²t mo₧nΘ pou₧φt v deklaraci ukazatele, nap°. zßpisem

 

int * restrict p;

 

Specifikuje, ₧e vztah mezi ukazatelem a prom∞nnou, na kterou tento ukazatel ukazuje, je v jistΘm smyslu omezen û zhruba °eΦeno, ₧e tuto prom∞nnou nebudeme m∞nit pomocφ ₧ßdnΘho dalÜφho ukazatele. To mß p°ekladaΦi umo₧nit ÜirÜφ optimalizace.

Pou₧itφ tohoto modifikßtoru dovolujφ pouze p°ekladaΦe BCXP a INT71; vzhledem k tomu, ₧e BCXP zatφm nepodporuje optimalizace, nemß jeho pou₧itφ v n∞m zattφm ₧ßdn² skuteΦn² v²znam.

Modifikßtor inline (6.7.4)

V²znam tohoto modifikßtoru je v podstat∞ stejn² jako v C++ û to znamenß, ₧e p°edstavuje nßstroj pro äruΦnφô optimalizaci. Standard ne°φkß, jak se mß funkce s tφmto modifikßtorem p°elo₧it, pouze naznaΦuje, ₧e by v²sledn² k≤d m∞l b²t co nejrychlejÜφ.

DneÜnφ p°ekladaΦe poskytujφ modifikßtor __inline se stejn²m v²znamem. Pouze p°ekladaΦe BCXP, INT71 a GNU znajφ standardem po₧adovan² tvar inline.

Nekonstantnφ hornφ mez pole (6.7.5.2)

Podle novΘho standardu lze v p°φpad∞ lokßlnφch nestatick²ch polφ zadat poΦet prvk∙, a tedy i hornφ mez indexu, nekonstantnφm v²razem. To znamenß, ₧e nßsledujφcφ deklarace je v C99 sprßvnß:

 

void f(int n)

{

            int A[n];            // Lze v C99

            // ...

            printf("%d", sizeof(A));

}

 

Zde se bude za b∞hu vyhodnocovat takΘ operßtor sizeof.

Tuto mo₧nost nabφzφ pouze p°ekladaΦe INT71 a GNU. V BCXP lze sice takΘ deklarovat pole s nekonstantnφ hornφ mezφ, pou₧ijeme-li vÜak na n∞ operßtor sizeof, p°ekladaΦ se zhroutφ.

Minimßlnφ poΦet prvk∙ pole (6.7.5.2)

Standard [1] dßle °φkß, ₧e deklarujeme-li pole jako parametr funkce, m∙₧eme urΦit, ₧e skuteΦn²m parametrem musφ b²t pole ze zadan²m minimßlnφm poΦtem prvk∙. K tomu slou₧φ klφΦovΘ slovo static uvedenΘ p°ed specifikacφ poΦtu prvk∙. Nap°φklad deklarace

 

void f(int A[static 3])

{

            // ...

}

 

°φkß, ₧e tΘto funkci musφme p°i volßnφ p°edat jako skuteΦn² parametr pole s nejmΘn∞ 3 prvky.

Tuto konstrukci nepodporuje ₧ßdn² z uveden²ch p°ekladaΦ∙. BCXP, INT71 a V03 ji ignorujφ (smφme ji pou₧φt, ale velikost p°edßvanΘho pole nekontrolujφ), ostatnφ hlßsφ chybu.

Pou₧itφ nedeklarovanΘ funkce (6.7.5.3)

SouΦasn² standard jazyka C zakazuje volat nebo jinak pou₧φvat funkci, kterß dosud nebyla deklarovßna. To znamenß, ₧e tradiΦnφ prvnφ program z uΦebnic jazyka C,

 

main()

{

            printf("hello, world");

}

 

je chybn², nebo¥ zde chybφ deklarace funkce printf() nebo vlo₧enφ hlaviΦkovΘho souboru <stdio.h>, kter² tuto deklaraci obsahuje. (Dßle uvidφme, ₧e je chybn² i z jinΘho d∙vodu.)

P°ekladaΦe BCPX a GNU oznaΦφ pou₧itφ nedeklarovanΘ funkce za chybu; p°ekladaΦ BC6, BCX a INT71 vypφÜφ varovßnφ, p°ekladaΦe VC02 a VC03 je tolerujφ bez nßmitek.

PojmenovanΘ iniciaizßtory (6.7.8)

Tato novinka umo₧≥uje inicializovat pouze vybranΘ slo₧ky struktur a polφ. Lze û Φi spφÜe m∞lo by b²t mo₧nΘ û ji takΘ pou₧φt k inicializaci kterΘkoli ze slo₧ek unie. (P°ipome≥me si, ₧e starÜφ standard dovolovat inicializovat pouze prvnφ slo₧ku uniφ.) Cel² trik spoΦφvß v tom, ₧e v inicializßtoru uvedeme jmΘno slo₧ky struktury Φi unie nebo index prvku pole, pak rovnφtko a za n∞ poΦßteΦnφ hodnotu prvku.V nßsledujφcφ ukßzce pou₧ijeme znovu strukturu Bubu, deklarovanou v jednom z p°edchozφch p°φklad∙:

 

struct Bubu y = {.x = 3};

int A[10] = {1,[7]=44};

 

Slo₧ky, kterΘ neinicializujeme explicitn∞, budou inicializovßny nulou, a to i v p°φpad∞ lokßlnφch automatick²ch prom∞nn²ch. (To ale nenφ ₧ßdnß novinka, to û vzdor n∞kter²m uΦebnicφm û platilo u₧ v p°edchozφ verzi standardu.)

PojmenovanΘ inicializßtory podporuje pouze BCXP a INT71.

Deklarace mezi p°φkazy (6.8)

Podobn∞ jako v C++, i v jazyce C nynφ smφme zapisovat deklarace kdekoli mezi p°φkazy. Tuto mo₧nost zatφm nabφzφ pouze p°ekladaΦe BCXP, INT71 a GNU.

Odstran∞n implicitnφ int (6.9.1)

Pravidlo, oznaΦovanΘ jako äimplicitnφ intô, umo₧≥ovalo v p°edchozφch verzφch jazyka vynechßvat klφΦovΘ slovo int v deklaracφch nßvratovΘho typu funkcφ, statick²ch prom∞nn²ch, konstant atd. Toto pravidlo bylo v souΦasnΘ verzi odstran∞no, tak₧e nelze napsat

 

const n = 1;            // Nynφ Üpatn∞

 

Mφsto toho je t°eba napsat

 

const int n = 1;

 

TakΘ p°φklad programu äHello, worldô o n∞kolik odstavc∙ v²Üe je nynφ Üpatn∞.

VÜechny testovanΘ p°ekladaΦe krom∞ BCXP, INT71 a GNU implicitnφ int tolerujφ bez nßmitek; GNU ho oznaΦφ za chybu, BCXP a INT71 vypφÜφ varovßnφ.

Zßkaz definice funkce pomocφ typedef (6.9.1)

Ve starÜφch verzφch jazyka C bylo mo₧no definovat funkci takto:

 

typedef int Fun();

Fun f {/* ... */}

 

Novß verze jazyka C to (po vzoru C++) zakßzala.

P°ekladaΦe BC6 a BCX to tolerujφ, ostatnφ (vΦetn∞ BCXP) to oznaΦφ za chybu. (Jde ovÜem o konstrukci, kterß do sluÜnΘho programovßnφ nepat°φ, nebo¥ celkem zbyteΦn∞ zhorÜuje Φitelnost programu.)

Makra s v²pustkou (6.10.3)

Standard nynφ dovoluje deklarovat makra s prom∞nn²m poΦtem parametr∙, kterΘ specifikujeme pomocφ v²pustky û nap°. takto:

 

#define ABC(a, ...) N∞jakß definice makra

 

S parametry, p°edan²mi pomocφ v²pustky, zachßzφme jako s celkem pomocφ identifikßtoru __VA_ARGS__.

Tuto mo₧nost nabφzφ pouze p°ekladaΦe BCXP, INT71 a GNU.

Komplexnφ Φφsla (7.3)

Jazyk C99 podle musφ implementovat t°i datovΘ typy pro reprezentaci komplexnφch Φφsel, a to float _Complex, double _Complex a long double _Complex. Spolu s nimi musφ poskytnout hlaviΦkov² soubor <complex.h>, je₧ bude obsahovat mj. makro I vyjad°ujφcφ imaginßrnφ jednotku, deklarace funkcφ pro prßci s komplexnφmi Φφsly atd.

KlφΦovΘ slovo _Complex a aritmetickΘ operace s komplexnφmi Φφsly implementujφ pouze p°ekladaΦe BCXP, INT71 a GNU.

GNU a INT71 vÜak nenabφzφ hlaviΦkov² soubor <complex.h>, tak₧e makro I a dalÜφ nßstroje si v n∞m obsa₧enΘ musφme implementovat sami. (Nenφ to t∞₧kΘ û lze pou₧φt nap°. unii pole dvou reßln²ch Φφsel odpovφdajφcφho typu a jednoho komplexnφho Φφsla.) Zde je vÜak t°eba p°ipomenout, ₧e INT71 vyu₧φvß hlaviΦkovΘ soubory microsoftsk²ch p°ekladaΦ∙.

P°φstup k v²poΦetnφmu prost°edφ (7.6)

Pod äv²poΦetnφm prost°edφmô se v tΘto souvislosti rozumφ nßstroje, kterΘ upravujφ chovßnφ procesoru p°i prßci s reßln²mi Φφsly û nap°. zda se zaokrouhluje v₧dy k nejbli₧Üφmu zobrazitelnΘmu Φφslu, v₧dy k nule apod. Na PC jde v podstat∞ o p°φstup ke stavovΘmu a °φdicφmu slovu matematickΘho koprocesoru.

Tyto nßstroje jsou soust°ed∞ny v hlaviΦkovΘm souboru <fenv.h>. Poskytujφ je pouze p°ekladaΦe BCXP a GNU.

Makro va_copy() (7.15)

Makro va_copy() by m∞lo b²t definovßno v hlaviΦkovΘm souboru <stdarg.h> a slou₧it ke kopφrovßnφ hodnoty typu va_list, je₧ se pou₧φvß pro prßci s parametry p°edßvan²mi pomocφ v²pustky. (Typ va_list je zpravidla typedef pro ukazatel na znakovΘ nebo celoΦφselnΘ prom∞nnΘ, a proto se v∞tÜina implementacφ jazyka C bez tohoto makra dosud obeÜla. Z°ejm∞ se vÜak vyskytujφ implementace, v nich₧ se pou₧φvß jin² mechanizmus p°φstupu k parametr∙m na mφst∞ v²pustky.)

Toto makro implementuje pouze p°ekladaΦ GNU. P°ekladaΦ BCXP se p°i pou₧itφ tohoto makra zhroutφ.

HlaviΦka <stdbool.h> (7.16)

Jazyk C podle novΘ normy obsahuje typ _Bool reprezentujφcφ logickΘ hodnoty. Je to celoΦφseln² typ s hodnotami 0 a 1 a v hlaviΦkovΘm souboru <stdbool.h> jsou #definovßna makra true a false se z°ejm²m v²znamem a n∞kterß dalÜφ.

Tento standardnφ hlaviΦkov² soubor poskytujφ pouze p°ekladaΦe BCXP a GNU. Typ _Bool najdeme i v INT71, ovÜem bez podp∙rnΘho hlaviΦkovΘho souboru.

HlaviΦka <stdint.h> (7.18)

Tato hlaviΦka poskytuje alternativnφ p°φstup k celoΦφseln²m typ∙m. Najdeme v nφ °adu deklaracφ typedef, je₧ definujφ typy jako int16_t, uint64_t apod., kterΘ umo₧≥ujφ volit datov² typ podle rozsahu, dßle typy jako int_least32_t se zaruΦen²m minimßlnφm rozsahem, typ intptr_t, do n∞ho₧ lze ulo₧it ukazatel a zφskat ho zp∞t beze ztrßty informace, typ ptrdiff_t pro rozdφl dvou ukazatel∙ atd.

Tento hlaviΦkov² soubor najdeme v p°ekladaΦφch BCX, BCXP a GNU; zb²vajφcφ p°ekladaΦe ho neposkytujφ.

K tomu je t°eba poznamenat, ₧e standard takΘ zavßdφ modifikßtory dΘlky z, resp. t pro tisk hodnot typ∙ size_t, resp. ptrdiff_t pomocφ funkcφ z rodiny printf(). Ty neimplementuje ani jeden z uveden²ch p°ekladaΦ∙.

Pokud jde o jazyk Cà

Je z°ejmΘ, pokud jde o implementaci novinek v jazyce C, je situace v p°φpad∞ prakticky pou₧iteln²ch p°ekladaΦ∙ pom∞rn∞ neut∞Üenß û ₧ßdn² z p°ekladaΦ∙ je neimplementuje v plnΘm rozsahu. To ovÜem m∙₧e b²t d∙sledek skuteΦnosti, ₧e v∞tÜina dodavatel∙ p°ekladaΦ∙ jazyka C++ se soust°edφ spφÜe na shodu se standardem C++ a jazyk C je pro n∞ jen jakousi nutnou p°φt∞₧φ.

Jazyk C++

Zde je, jak jsme si u₧ °ekli, situace mnohem veselejÜφ; to ale neznamenß, ₧e je doopravdy dobrß. V Φlßnku Sedm kohout∙ na smetiÜti v tiÜt∞nΘm Chipu jsme pro porovnßnφ zvolen²ch p°ekladaΦ∙ pou₧ili nßsledujφcφ rysy jazyka C++:

Zde se podφvßme jeÜt∞ na dalÜφ osv∞dΦenß äbolavß mφstaô p°ekladaΦ∙. Jsou to:

Poslednφ dva body jsou podobnΘ jako v p°φpad∞ jazyka C99. Tabulka 2 obsahuje v²sledky pro vÜechny porovnßvanΘ p°ekladaΦe.

 

  BC6 BCX BCXP GNU INT71 VC02 VC03 ISO
KlφΦovß slova iso646 <iso646> <iso646> <iso646> ano <iso646> <iso646> <iso646> 2.11
Koenigovo vyhledßvßnφ ano ano jen op. ano ano jen oper. ano 3.4.2.
Obor deklarace v if ano (?) ano (?) ano ne ano ne ano 6.4
Implicitnφ int toleruje toleruje toleruje chyba varovßnφ toleruje toleruje 7.1
Typedef funkce toleruje toleruje chyba chyba chyba   chyba 8.3.5.
Exportnφ Üablony ne ne ano ne ne ne ne 14.
Vno°enΘ Üablony ano ano ano ano ano jen inline ano 14.5.2.
Parcißlnφ specializace ano ano ano ano ano ne ano 14.5.4.
Parcißlnφ °azenφ ano ano ano ano ano ne ano 14.5.5.2
Specifikace throw ano ano ano ano ne ne ne 15.4
uncaught_exception ano ano ne ano ano ne ano 18.6.4.

 

JednotlivΘ polo₧ky v nφ jsou op∞t se°azeny podle po°adφ, v jakΘm jsou ve standardu uvedeny.

Poznßmky

I tentokrßt budeme postupovat podle po°adφ, v n∞m₧ jsou jednotlivΘ body uvedeny v tabulce 2. ╚φsla za nadpisy odkazujφ tentokrßt na odpovφdajφcφ pasß₧ standardu [2].

KlφΦovß slova podle ISO 646 (2.11)

Zdaleka ne vÜechny nßrodnφ klßvesnice obsahujφ znaky &, | atd. Proto nabφzφ standard [2] mo₧nost alternativnφho vyjßd°enφ operßtor∙ &&, || a aj. pomocφ klφΦov²ch slov and, or a dalÜφch.

Tuto mo₧nost poskytuje pouze p°ekladaΦ GNU. V ostatnφch musφme postupovat stejn∞ jako v jazyce C û pou₧φt hlaviΦkov² soubor <iso646.h>, kter² umo₧≥uje nßhradu t∞chto klφΦov²ch slov makry.

Koenigovo vyhledßvßnφ (3.4.2)

Jako Koenigovo vyhledßvßnφ se oznaΦuje vyhledßvßnφ nekvalifikovan²ch jmen p°etφ₧en²ch operßtor∙ a funkcφ v prostorech jmen jejich parametr∙, i kdy₧ tyto prostory jmen nebyly zp°φstupn∞ny deklaracφ nebo direktivou using. To znφ mo₧nß slo₧it∞, ale jde v podstat∞ o jednoduchΘ pravidlo, kterΘ si nejlΘpe ukß₧eme na nßsledujφcφm p°φkladu.

 

namespace Alfa

{

  struct X{};

  void f(X){}

  X operator+(X x, X y) {return y;}

}

 

int main(  )

{

  Alfa::X a, b, c;

  f(a);

  c = a+b;

  return 0;

}

 

Funkce main() le₧φ mimo jak²koli prostor jmen. Funkci f() a operßtor + p°etφ₧en² pro typ Alfa::X jsme ve funkci main() pou₧ili bez kvalifikace identifikßtorem prostoru jmen. P°esto se program p°elo₧φ a z funkce main() zavolß opravdu Alfa::f() a Alfa::operator+(), nebo¥ p°ekladaΦ bude jmΘna t∞chto funkcφ a operßtor∙ hledat nejen v kontextu pou₧itφ (tj. zde mimo prostory jmen), ale i v kontextu operand∙, zde tedy v prostoru jmen Alfa.

P°ekladaΦe BCXP a VC02 implementujφ Koenigovo vyhledßvßnφ pouze pro operßtory (tak₧e volßnφ funkce f() v p°edchozφm p°φkladu oznaΦφ za chybnΘ); zb²vajφcφ p°ekladaΦe ho implementujφ v souladu se standardem.

Obor deklarace prom∞nnΘ v p°φkazu if  (6.4)

V podmφnce p°φkazu if, stejn∞ jako v podmφnce p°φkaz∙ while, smφme deklarovat prom∞nnou. Tuto prom∞nnou vÜak nesmφme p°edefinovat ve vno°en²ch blocφch nejvyÜÜφ ·rovn∞. To znamenß, ₧e nap°. konstrukce

 

if(int i = f()){ int i = g(); /* ... */ }

 

je nesprßvnß, zatφmco konstrukce

 

if(int i = f()){{ int i = g(); /* ... */ }}

 

u₧ je p°φpustnß, nebo¥ opakovanß deklarace prom∞nnΘ i je ve vno°enΘm bloku ni₧Üφ ·rovn∞. Podobnß omezenφ platφ i pro p°φkaz while.

Chybnou deklaraci prom∞nnΘ v p°φkazech if a while ohlßsφ vÜechny testovanΘ p°ekladaΦe krom∞ GNU a VC02.

K tomu je ale t°eba poznamenat, ₧e p°ekladaΦe BC6, BCX a BCXP oznaΦφ za chybnou i sice nesmyslnou, ale syntakticky sprßvnou konstrukci

 

if(int i = f()){{ int i = g(); }}

 

(TakovΘhle v∞ci mohou v  programu vzniknout, jestli₧e hledßte chybu a postupn∞ odstra≥ujete Φßsti k≤du, o nich₧ vφte, ₧e jsou v po°ßdku.)

Implicitnφ int (7.1)

O tomto pravidlu jsme ji₧ hovo°ili v souvislosti s jazykem C99. V jazyce C++ bylo zakßzßno podstatn∞ d°φve ne₧ v jazyce C, u₧ v poΦßteΦnφch fßzφch p°φpravy standardu; to ale neznamenß, ₧e to p°ekladaΦe dodr₧ujφ. Pouze p°ekladaΦ GNU ohlßsφ chybu a p°ekladaΦ INT71 ohlßsφ varovßnφ, ostatnφ ho tolerujφ bez nßmitek. Chovßnφ p°ekladaΦe INT71 je z°ejm∞ nejrozumn∞jÜφ, nebo¥ implicitnφ int byl dlouhß lΘta souΦßstφ cΘΦka°skΘho folkl≤ru.

Zßkaz definice funkce pomocφ typedef (8.3.5)

TakΘ o tomto pravidle jsme ji₧ hovo°ili v souvislosti s jazykem C a takΘ tento zßkaz platil v C++ ji₧ poΦßteΦnφch fßzφch p°φpravy standardu. P°ekladaΦe BC6 a BCX tuto odchylku od standardu tolerujφ, ostatnφ ji zakazujφ.

Exportnφ Üablony (14)

Jde o jednu z mßla souΦßstφ standardu jazyka C++, kterß nevznikla z iniciativy u₧ivatel∙, tohoto jazyka, ale jako v²sledek prßce standardizaΦnφ komise. Jde takΘ o jednu z nejproblematiΦt∞jÜφch souΦßstφ, a proto ji dodnes v∞tÜina p°ekladaΦ∙ neimplementuje.

Nenφ tedy divu, ₧e exportnφ Üablony neimplementuje ₧ßdn² z porovnßvan²ch p°ekladaΦ∙. V dokumentaci k BCXP se o nich sice hovo°φ, integrovanΘ v²vojovΘ prost°edφ toto klφΦovΘ slovo rozeznßvß, ale p°ekladaΦ ho odmφtß.

Vno°enΘ Üablony(14.5.2)

Deklarace Üablony m∙₧e b²t vno°ena do deklarace t°φdy nebo Üablony t°φdy. P°itom v obklopujφcφ Üablon∞ m∙₧eme uvΘst pouze hlaviΦku Üablony metody, m∙₧eme ji tam ale takΘ zapsat celou. V nßsledujφcφm p°φkladu jsou sprßvnΘ ob∞ mo₧nosti:

 

template <typename T> class Alfa

{

  public:

  template <typename T1> bool F();           

  template <typename T2> int G(T2 x)

  {

    return (int)x;

  }

};

 

template <typename T>

template <typename T1> bool Alfa<T>::F()

{

  return true;

}

 

èablona metody F() je definovßna mimo t∞lo Üablony Alfa<T>, Üablona metody G() je definovßna uvnit°.

P°ekladaΦ VC02 dovoluje pouze druhou mo₧nost û definice vno°enΘ Üablony musφ b²t vno°ena do definice obklopujφcφ Üablony. Ostatnφ p°ekladaΦe implementujφ vno°enΘ Üablony v plnΘm rozsahu.

Parcißlnφ specializace Üablon t°φd (14.5.4)

Parcißlnφ specializace Üablon t°φd umo₧≥uje definovat zvlßÜtnφ implementaci Üablony objektovΘho typu pro urΦitΘ hodnoty parametr∙. Nejprve musφme definovat obecnou Üablonu platnou pro vÜechny hodnoty parametr∙, pro n∞₧ nestanovφme v²jimku pomocφ parcißlnφ specializace, pak mohou nßsledovat specializovanΘ Üablony. Nap°φklad takto:

 

// Obecnß Üablona

template <typename T, int N>

class Beta

{

  public:

    int f(){}

};

 

// Parcißlnφ specializace pro N==0

template <typename T>

class Beta<T, 0>

{

  public:

    void f(){}

    void g(){}

};

 

P°ekladaΦ pou₧ije v₧dy nejspecializovan∞jÜφ verzi Üablony, tj. tu, jejφ₧ formßlnφ parametry nejvφce odpovφdajφ typ∙m a hodnotßm v deklaraci.

Parcißlnφ specializaci podporujφ vÜechny porovnßvanΘ p°ekladaΦe s v²jimkou VC02.

Parcißlnφ °azenφ Üablon obyΦejn²ch funkcφ (14.5.5.2)

Pro Üablony obyΦejn²ch funkcφ (tj. funkcφ, kterΘ nejsou metodami objektov²ch typ∙) nelze pou₧φt mechanizmus parcißlnφ specializace. Lze je vÜak p°et∞₧ovat a p°itom pou₧φt mechanizmu parcißlnφho °azenφ: p°ekladaΦ pou₧ije tu ze Üablon, jejφ₧ parametry nejvφce odpovφdajφ skuteΦn²m parametr∙m zadan²m p°i volßnφ funkce. Podφvejme se na p°φklad:

 

template<typename T> void f(T a){}        // (1)

template<typename T> void f(T* a){}       // (2)

template<typename T> void f(const T* a){} // (3)

 

int main()

{

  int a = 5;

  int *p = &a;

  const int *cp = p;

  f(a);         // volß (1)

  f(p);         // volß (2)

  f(cp);        // volß (3)

  return 0;

}

 

Tento mechanizmus implementujφ vÜechny porovnßvanΘ p°ekladaΦe s v²jimkou VC02.

Specifikace typu v²jimek v deklaraci funkce (15.4)

V deklaraci funkce lze specifikovat typ v²jimek, kterΘ se z nφ mohou rozÜφ°it. K tomu slou₧φ klφΦovΘ slovo throw zapsanΘ za hlaviΦku funkce, za nφm₧ nßsleduje v zßvorkßch seznam dovolen²ch typ∙ v²jimek. Prßzdn² seznam znamenß, ₧e se z danΘ funkce nesmφ rozÜφ°it ₧ßdnß v²jimka; vynechanß specifikace znamenß, ₧e se z funkce smφ rozÜφ°it jakßkoli v²jimka.

Typ v²jimky se kontroluje za b∞hu; rozÜφ°φ-li se z funkce v²jimka nedovolenΘho typu, zavolß program standardnφ funkci unexpected(), kterß typicky ukonΦφ program.

P°ekladaΦ INT71 dovoluje tuto specifikaci pou₧φt, ignoruje ji vÜak. VC02 a VC03 dovolujφ tyto specifikace pou₧φt, vyu₧ijφ vÜak pouze specifikaci throw(), je₧ °φkß, ₧e se z funkce nesmφ rozÜφ°it ₧ßdnß v²jimka.

Funkce uncaught_exception() (18.6.4)

Tato funkce by m∞la um∞t urΦit, zda byla volßna za änormßlnφch okolnostφô nebo p°i ·klidu zßsobnφku v dob∞ mezi vznikem v²jimky a jejφm zachycenφm vhodn²m handlerem.

Implementujφ ji vÜechny porovnßvanΘ p°ekladaΦe; ovÜem v BCXP a VC02 (a takΘ INT71, je-li instalovßn spolu s VC02) vracφ v₧dy false, tak₧e ji nelze vyu₧φt.

Efektivita p°elo₧enΘho k≤du

V tomto porovnßvßnφ vynechßme p°ekladaΦ BCXP, nebo¥ mj. nenabφzφ mo₧nost optimalizace p°elo₧enΘho k≤du. Vedle toho trpφ °adou dalÜφch nedostatk∙ û nap°. hlaviΦkov² soubor <sys\timeb.h> obsahuje deklaraci funkce ftime(), kterß v knihovn∞ chybφ, p°i pou₧itφ n∞kter²ch konstrukcφ se p°ekladaΦ hroutφ atd.

Testovacφ programy

Pro porovnßnφ jsme pou₧ili nßsledujφcφ programy, kterΘ ukazujφ r∙znΘ strßnky optimalizace û prßci s reßln²mi Φφsly, prßci s pam∞tφ, efektivitu vstupnφch a v²stupnφch operacφ atd.

ProblΘm 13 dam

Jde o klasickou kombinatorickou ·lohu, kterou formuloval n∞meck² matematik K. F. Gauss n∞kdy p°ed rokem 1850. Cφlem je rozmφstit n dam na Üachovnici s n n poli tak, aby se navzßjem neohro₧ovaly. (To nemß nic spoleΦnΘho se Üachem, p°ipomφnß to spφÜe skuteΦn² ₧ivot).

Snadno zjistφte, ₧e pro Üachovnici 4 ╫ 4 mß tato ·loha pouhß 2 °eÜenφ; pro Üachovnici 8 ╫ 8 jich je ji₧ 92 a pro Üachovnici 13 ╫ 13 jich je p°es 70 000. NßÜ program nevypisuje jednotlivß °eÜenφ, pouze zjiÜ¥uje jejich poΦet (nejde nßm o test vstupnφch a v²stupnφch operacφ). Jßdrem programu je nßsledujφcφ funkce:

 

void vyres(int m)

{

if(m == n) PocRe++;

     else

for(int k = 0; k < n; k++)

{

if(Bezpecne(k,m))

{

X[m] = k;

vyres(m+1);

}

}

X[m] = -1;

}

 

Pole X[] obsahuje polohy dam v jednotliv²ch sloupcφch Üachovnice, funkce Bezpecne() uvracφ true, pokud lze dßmu na danΘ pole umφstit, tj. pokud ji na n∞m ₧ßdnß z d°φve umφst∞n²ch dam neohro₧uje.

╚tenφ a v²pis reßln²ch Φφsel

Tento program p°eΦte 30 000 reßln²ch Φφsel ze souboru a ihned je vypφÜe na konzolu. Takto testujeme jak standardnφ vstupnφ a v²stupnφ nßstroje z jazyka C (funkce scanf() a printf()), tak i objektovΘ datovΘ proudy cout a cin z C++. Vstupnφ data Φteme ze souboru pomocφ p°esm∞rovßnφ, zadanΘho v p°φkazovΘm °ßdku, a v²stup sm∞°uje na konzolu.

Tento program v podstat∞ testuje kvalitu implementace formßtovacφch operacφ.

Samotn² vstup a v²stup obstarßvajφ slu₧by operaΦnφho systΘmu. Mohlo by se tedy zdßt, ₧e v t∞chto operacφch nebude mezi jednotliv²mi p°ekladaΦi ₧ßdn² zßva₧n² rozdφl. Rozdφlnost v²sledk∙, shrnut²ch v tabulce 3, vÜak ukazuje, ₧e formßtovacφ operace zabφrajφ podstatnou Φßst pot°ebnΘho Φasu. To znamenß, ₧e v tomto testu porovnßvßme zaprvΘ kvalitu implementace formßtovacφch operacφ a zadruhΘ kvalitu optimalizace t∞chto operacφ.

Prßce s pam∞tφ

K otestovßnφ prßce s pam∞tφ pou₧φvßme zapl≥ovßnφ a vyprazd≥ovßnφ spojovΘho seznamu: Do seznamu 10000krßt ulo₧φme 1000 cel²ch Φφsel a pak tento seznam vyprßzdnφme.

K tomu pou₧φvßme vlastnφ velice jednoduchou (a jedno·Φelovou) implementaci jednosm∞rn∞ z°et∞zenΘho seznamu:

 

// Prvek spojovΘho seznamu

class prvek 

{

         long data;

         prvek * dalsi;

public:

         prvek(long i, prvek* d=0): dalsi(d), data(i){}

         prvek* Dalsi(){ return dalsi; }

};

 

class seznam

{

         prvek *hlava;

public:

         void vloz(long y);

         seznam() : hlava(new prvek(0,0))

         {

                  if(!hlava) Chyba();

         }

         ~seznam();       // Vyprßzdnφ seznam

};

 

Kdybychom pou₧ili standardnφ Üablonu list<T>, zßvisely by v²sledky nejen na p°ekladaΦi, ale i na pou₧itΘ implementaci standardnφ knihovny, a tomu se zde chceme vyhnout.

PoΦφtßnφ s reßln²mi Φφsly

Jazyky C a C++ se Φasto pou₧φvajφ i pro numerickΘ v²poΦty; i kdy₧ v tΘto oblasti zatφm stßle dominuje Fortran, prosazuje se C a C++ Φφm dßl vφce.

Testovacφ program °eÜφ soustavu 40 lineßrnφch algebraick²ch rovnic o 40 neznßm²ch. Jde o soustavu, kterß vznikne p°i °eÜenφ Poissonovy rovnice na jednotkovΘm Φtverci metodou sφtφ. Koeficienty tΘto soustavy se pravideln∞ opakujφ, tak₧e nenφ t°eba uklßdat v pam∞ti.

K °eÜenφ jsme pou₧ili GaussovuûSeidlovu iteraΦnφ metodu.

Jßdrem programu je nßsledujφcφ funkce IteracniKrok(), kterß obstarß jeden iteraΦnφ krok:

 

double IteracniKrok()

{

double r = 0;

for(int i = 1; i < N; i++)

for(int j = 1; j < N; j++)

{

double d = (A[i+1][j] + A[i-1][j] +

A[i][j+1] + A[i][j-1])*0.25

 + sqr(s)*0.25*g(i*s, j*s);

r += sqr(d-A[i][j]);

A[i][j] = d;

}

return r;

}

 

Tato funkce vracφ souΦet druh²ch mocnin rozdφl∙ slo₧ek A[i][j] °eÜenφ vypoΦten²ch v tomto a v p°edchozφm kroku.

╪eÜenφ A je ulo₧eno ve dvojrozm∞rnΘm poli, nebo¥ jeho slo₧ky p°edstavujφ hodnoty hledanΘ funkce v bodech sφt∞ polo₧enΘ na jednotkov² Φtverec. Funkce g() p°edstavuje pravou stranu Poissonovy rovnice, funkce sqr() poΦφtß druhou mocninu p°edanΘ hodnoty.

Efektivita implementace v²jimek

V²jimky by m∞ly slou₧it pouze k °eÜenφ v²jimeΦn²ch situacφ. Z toho plyne, ₧e by jejich oÜet°ovßnφ nem∞lo zabφrat p°evß₧nou Φßst doby b∞hu programu. P°esto je t°eba se zab²vat takΘ efektivitou jejich implementace û kdy₧ u₧ nic jinΘho, tak proto, abychom m∞li jasnou p°edstavu, jak jsou nßroΦnΘ. ObΦas se toti₧ lze setkat s p°edstavou, ₧e v²jimky p°edstavujφ alternativu k b∞₧nΘmu nßvratu z funkce a ₧e by bylo vhodnΘ je takov²mto zp∙sobem vyu₧φvat.

Testovacφ program srovnßvß volßnφ funkce, kterß vracφ konstantnφ v²sledek b∞₧n²m zp∙sobem, a volßnφ funkce, kterß vracφ stejn² v²sledek pomocφ v²jimky.

 

double pinorm()

{

        return 3.141;

}

 

double pithr()

{

        throw 3.141;

}

 

Tyto funkce jsou volßny 100000krßt.

M∞°enφ Φasu

Dobu pot°ebnou pro jednotlivΘ testovacφ programy jsme m∞°ili takto:

 

int main()

{

/* P°φpravnΘ operace */

timeb T1, T2; 

ftime(&T1);      // ZaΦßtek m∞°enφ

/* Zde je m∞°en² ·sek programu */

ftime(&T2);      // Konec m∞°enφ

// V²stup v²sledku

cout << (T2.time+T2.millitm*0.001) û

            (T1.time+T1.millitm*0.001)

return 0;

}

 

Funkce ftime()nenφ souΦßstφ standardu, je vÜak natolik b∞₧n²m rozÜφ°enφm, ₧e ji implementujφ vÜechny testovanΘ p°ekladaΦe.

PoΦφtaΦ

Tato fakta jsme uvedli ji₧ v Φlßnku Sedm kohout∙ na smetiÜti v tiÜt∞nΘm Chipu; pro pohodlφ Φtenß°e je ale zopakujeme.

Testovacφ programy jsme spouÜt∞li na PC vybavenΘm procesorem Athlon/1 GHz s 512 MB RAM pod operaΦnφm systΘmem Windows 2000. Ka₧d² program jsme spustili desetkrßt jako jedinou aplikaci v dosovΘm okn∞ a tabulka 3 ukazuje pr∙m∞ry dosa₧en²ch Φas∙ v sekundßch.

  CB6 CBX GNU INT71 VC02 VC03
13 dam 7,5 7,5 13,8 5,5 6,1 6,0
stdio 6,6 3,4 3,2 3,0 2,6 3,0
iostream 7,2 8,2 11,2 8,5 2,6 8,5
pam∞¥ 3,0 2,9 7,2 5,3 5,3 5,0
soustava 2,4 1,6 2,8 1,6 1,3 1,9
v²jimky 0,8 7,4 1,7 0,6 0,5 0,6

I kdy₧ jsou dosa₧enΘ Φasy pom∞rn∞ vyrovnanΘ, lze z nich zφskat p°edstavu o kvalit∞ porovnßvan²ch p°ekladaΦ∙.

Kter² kohout zvφt∞zil?

Ani porovnßnφ zahrnujφcφ vφce kritΘriφ nßm neumo₧≥uje dßt na tuto otßzku jednoznaΦnou odpov∞∩. NaÜe zßv∞ry budou stejnΘ jako v tiÜt∞nΘm Chipu:

Odkazy

[1] International Standard ISO/IEC 9899:1999. Programming Languages û C.

[2] International Standard ISO/IEC 14882:1998. Programming Languages û C++

Miroslav Virius