Tak jsem opět zde a s druhou úlohou. Tentokrát si dáme něco "napříč spektrem norem" a budeme programovat jak v C, tak v C++. Myslím si, že vás to zaujme :).
Zadání
Napište program, který po zkompilování vypíše, podle jaké normy byl zkompilován. Berte v potaz normy ANSI-C (c89), ISO-C (c99) a ISO-C++ (c++98).
Vzorový výstup (GCC):
$ gcc -std=c89 -pedantic -o prog prog.c $ ./prog c89 $ gcc -std=c99 -pedantic -o prog prog.c $ ./prog c99 $ g++ -std=c++98 -pedantic -o prog prog.c $ ./prog c++98
Existuje více správných řešení, takže pokud už někdo s řešením přišel před vámi, můžete zkusit vymyslet řešení nové.
Omezení
Celý program musí být v 1 souboru, musí jej být možné přeložit podle všech tří zmíněných norem a spustit přesně jako ve vzorovém výstupu (lze ovšem využít i jiný překladač). Dále by program měl být implementačně nezávislý (tj nepoužívejte konstrukty s nespecifikovaným či nedefinovaným chováním). Nesmíte použít žádná předdefinovaná makra překladačem (jako __STDC__ apod.) ani direktivy pro podmíněný překlad (kromě direktivy #include a #define pro vytvoření svých vlastních symbolických konstant), neboli nic, co by splnění tohoto úkolu příliš usnadnilo. Rád zodpovím případné dotazy, co se těchto omezení týče.
"Prémiové body"
Pro zisk (bezvýznamných :]) prémiových bodů upravte stávající program tak, aby "rozeznal", že byl přeložen i podle (draftu) normy C++0x (pro odzkoušení lze využít např. překladač GCC 4.4, který část tohoto draftu implementuje). Mě se nepodařilo přijít na to, jak toho docílit, takže v případě, že se to někomu povede, tak se alespoň přiučím :).
Řešení
Jedno z možných řešení:
#include <stdio.h> int x[100]; int main() { int a; struct x {int i;}; a = 2 //* */ +2; switch (a) { case 4: if (sizeof(x) == sizeof(struct x)) printf("c++98\n"); else printf("c99\n"); break; case 1: printf("c89\n"); break; } return 0; }
Teď se podíváme, jak toto řešení funguje. Rozdíl mezi C99 a C++98 je řešen pomocí kódu:
int x[100]; int main() { struct x {int i;}; // ... if (sizeof(x) == sizeof(struct x)) printf("c++98\n"); else printf("c99\n"); // ... }
V C99 (i ANSI-C) jsou totiž identifikátory struktur umisťovány do odlišného "prostoru jmen" (nejedná se ovšem o namespaces, jak je znáte z C++) oproti ostatním datovým typům, takže při práci s nimi je třeba kvalifikovat prostor jmen pomocí klíčového slova struct. Takže pokud vytvoříme globální proměnnou x typu pole čísel typu int a dále lokální proměnnou typu struct x, tak v případě C99 (a ANSI-C) nedojde k zastínění identifikátoru x globální proměnné (v případě C++98 ovšem ano), tudíž sizeof(x) == sizeof(struct x) vrátí jiný výsledek v případě C99/ANSI-C a C++98.
Rozdíl mezi ANSI-C a C99 je řešen pomocí kódu:
int main() { int a; a = 2 //* */ +2; switch (a) { case 4: // C99 nebo C++98 break; case 1: printf("c89\n"); break; } return 0; }
Zde se využívá toho, že v ANCI-C neexistují řádkové komentáře //, takže při překladu podle tohoto standardu bude výsledkem a = 2 / +2;, což je 1. V případě C99 a C++98 bude (díky tomu, že se lexikálního analyzátor vždy snaží zpracovat co nejdelší sekvenci znaků, která ještě tvoří lexém) výpočet jiný, čili a = 2 +2;, což je 4.
Nepřenositelná řešení
Někoho by možná mohlo napadnout využít (pro odlišení C99 a C++98) tyto odlišnosti:
sizeof(’c’) == sizeof(int); // C99 sizeof(’c’) == sizeof(char); // C++98
nebo
enum e { A }; sizeof(A) == sizeof(int); // C99 sizeof(A) == sizeof(e); // v C++98 se sizeof(A) může lišit od sizeof(int)
Problém je zde s nepřenositelností výše zmíněných konstrukcí. C99 ani C++98 totiž nepředepisuje přesnou velikost jednotlivých datových typů (pouze předepisuje několik pravidel, např. že char má alespoň 8 bitů a int má alespoň 16 bitů a platí sizeof(int) >= sizeof(char)) a tudíž (teoreticky) může nastat situace, že v dané implementaci bude platit sizeof(char) == sizeof(int) a první "řešení" nebude fungovat. Obdobným neduhem trpí druhé "řešení".
Řešení
Re: Řešení
Pekne - reseni je spravne :).
Zveřejněno moje řešení #2
Zveřejnil jsem moje komentované řešení druhého úkolu.