Konvence pro programování v jazyku C/C++

(verze platná od podzimního semestru 2009)

Části vyznačené fialově se týkají pouze jazyka C++. Tučnou kurzívou jsou vyznačena důležitá místa, červeně případná místa změněná proti původní verzi zveřejněné na počátku semestru.

Aby se snížilo riziko chyb v programu a zdrojový text programu byl srozumitelnější, je velmi žádoucí řídit se při programování určitými konvencemi. Některé z nich jsou dokonce vyžadovány normou jazyka C, resp. C++. V příkladech, které budete zpracovávat ve cvičení a ke zkoušce je dodržování všech dále uvedených konvencí vyžadováno.

Za normu se v současné době považuje ISO/IEC C (zvané C99) pro jazyk C, ANSI/ISO C++ pro jazyk C++.

Zejména se doporučuje:

  1. Zdrojový kód bohatě komentovat. Pomůže to nejen jiným programátorům, kteří budou případně Váš program "luštit", ale i vám samým, pokud se k němu budete nuceni za čas vrátit. Můžete používat komentáře ve tvaru /* komentář */ (vhodné pro víceřádkové komentáře), nebo // komentář (vhodné pro krátké komentáře).
  2. Není-li to absolutně nutné, nepoužívejte nenormalizované prvky jazyka, i když je vámi používaný překladač akceptuje. Nevíte, kdy budete nuceni program přenést na jinou platformu nebo změníte používaný překladač.
  3. Funkce main vrací vždy hodnotu typu int. Občas (i v učebnicích) můžete spatřit deklaraci void main(), ale ta neodpovídá ani klasickému Céčku Kernighana-Ritchieho, ani žádné z norem jazyka C, ani normě jazyka C++ (přestože mnoho překladačů ji akceptuje bez varování).
  4. Vzhledem k předchozímu bodu je třeba, aby funkce main rovněž určila hodnotu, která se má vrátit. Je zvykem vracet nulu, pokud program při zpracování nezjistil chybu a malé kladné číslo, pokud na chybu narazil. Konkrétní hodnotou je vhodné rozlišit jednotlivé typy chyb (např. chybné volání programu, chybná data, neexistenci řešení apod.) Pokud program zpracovává několik příkladů, přičemž některá data zpracoval bez problémů a v jiných zjistil chybu, je třeba indikovat návratovou hodnotou chybu (není špatný nápad vrátit počet chybných dat). K předepsání návratové hodnoty se používá příkaz return číslo;
  5. Návratová hodnota funkce main je sice formálně typu int, ale aby ji správně zpracoval shell operačního systému, je třeba omezit se na hodnoty od 0 do 255. Zejména je nevhodné uvádět hodnoty záporné; např. -1 shell obvykle pochopí jako 255.
  6. Program je vhodné členit na funkce provádějící dílčí části algoritmu; (v objektovém programování je to prakticky nezbytné).
  7. Pro volané funkce je vhodné na začátek programu uvést jejich prototypy. U knihovních funkcí to zajistí odpovídající direktiva #include, pro vlastní funkce napište deklaraci prototypu sami. Pokud zadání vyžaduje vytvoření samostatného hlavičkového souboru, soustřeďte v něm deklarace všech prototypů. Hlavičkový soubor do všech částí programu (zdrojových souborů) zahrnete direktivou #include "název.h". Název hlavičkového souboru bude až na příponu totožný s názvem programu. Hlavičkový soubor může obsahovat rovněž potřebné globální deklarace (zejména deklarace tříd v C++), pomocí direktivy #ifndef nebo #ifdef zajistěte, aby se do programu deklarace proměnných uložily pouze jednou. Pozor - pro funkce a metody se do hlavičkového souboru vkládají pouze předběžné deklarace, definiční deklarace budou až v souboru s příponou .c nebo .cc
  8. Standardní hlavičkové soubory jazyka C++ nemají podle normy příponu .h obvyklou v jazyce C, ale i u starších překladačů C++, ale jsou bez přípony. Většina překladačů zná oba druhy hlavičkových souborů, ale ty se od sebe v detailech liší. Staré standardní hlavičkové soubory s příponou nepoužívejte. Naproti tomu našim vlastním hlavičkovým souborům je třeba příponu .h dát.
  9. Formální úprava zdrojového kódu může výrazně zlepšit jeho srozumitelnost a přispívá i k odhalení chyb. Nešetřete proto mezerami pro odsazování podřízených syntaktických konstrukcí a jasně tak vyznačujte, kde končí která vnořená konstrukce. Na druhé straně počtem mezer neplýtvejte, pro dostatečnou přehlednost stačí odsazovat každý stupeň o 2 mezery. Doporučuje se, aby délka řádku nepřekročila 120 znaků (jazyk poskytuje dostatek možností, jak zkrátit dlouhé řádky pro zápis na potřebnou délku). Tabulátor přitom považujte ve shodě s obvyklými programy pro výpis textu za 8 mezer, ale raději se mu vyhněte úplně. (Omezení délky na 120 znaků není samoúčelné - ne každý cvičící má k dispozici obrazovku, kde jsou dostatečně čitelné dlouhé řádky psané vynuceně malým písmem.)
  10. Podobně výstupy formátujte tak, aby byly optimalizovány pro terminál o 24 řádcích po 120 znacích. Na konci má program zanechat kursor na novém řádku.
  11. I když jazyk C++ v sobě obsahuje i prostředky pro vstup a výstup známé z jazyka C, až na odůvodněné výjimky jich nepoužívejte a nahraďte je používáním operátorů <<  a >>, případně V/V funkcí jazyka C++. Podobně nepoužívejte jiné prvky jazyka C tam, kde má C++ k dispozici vhodnější nástroje (např. funkcím a operátorům z hlavičkového souboru <string> dáváme přednost před prostředky ze <string.h> nebo <cstring>).
  12. Každý program by měl před čtením ze standardního vstupu vypsat pokyny, jaká data očekává. Přečtená data by pak měl pro kontrolu opsat. (Data se nemusí vždy číst z klávesnice, na úrovni operačního systému může být vstup přesměrován na soubor a zadávané hodnoty nejsou potom na monitoru vidět.) To platí i v případě, kdy program ohlásí, že data jsou chybná - tam je tato informace ještě cennější.
  13. Předchozí pravidlo není vhodné dodržovat vždy bez výjimky. Např. u programů, které vyhledávají data v (potenciálně rozsáhlé) databázi by bylo nesmyslné celou databázi pro kontrolu opisovat - zde postačí opsat zadané vyhledávací kritérium a vypsat záznamy, které mu odpovídají. Podobně postupujte i v jiných případech, kdy rozsah vstupních dat výrazně převyšuje rozsah dat výstupních.
  14. Jednotlivé položky vstupních dat je zvykem na vstupu oddělovat od sebe "bílým znakem" nebo kombinací více bílých znaků (např. mezera, 5 mezer, nový řádek, tabulátor, nový řádek a po něm tabulátor apod.) Vaše programy musí akceptovat jakýkoli z těchto způsobů oddělení.
  15. Srozumitelnosti přispívá vhodná volba názvů proměnných, funkcí, tříd, šablon a jiných entit. Mnemotechnické názvy - např. pocet_bodu nebo sumarizace() - jsou rozhodně vhodnější než názvy, které nic neříkají - jako nb nebo S(). Šetřit na délce názvů přinese víc problémů než úspor.
  16. Proměnné je vhodné deklarovat lokálně uvnitř funkce; pouze ty, které se budou používat ve více funkcích a není účelné je předávat jako parametry, deklarovat jako globální.
  17. Pro speciální datové typy (například struktury) je vhodné v jazyce C použít příkaz typedef, v C++ je mnohem vhodnější zavést vlastní třídu.
  18. U velkých projektů je vhodné použít rozdělení kódu do více souborů a překládat pomocí utility make. U příkladů v jazyce C to však ve cvičeních ani v závěrečných příkladech nepoužívejte, pokud to zadání výslovně nevyžaduje. V C++ bude vyžadováno, aby příklady neobsahující vlastní třídy a šablony byly zapsány v jednom souboru (a k němu byl případně podle bodu 7 přidán hlavičkový soubor). V příkladech obsahujících deklarace tříd nebo šablon budou v jednom souboru (zadaného názvu) zapsány všechny takové deklarace a další potřebné funkce a ve druhém bude pouze hlavní program sloužící pro otestování vytvořených tříd a šablon. Tento druhý soubor bude mít stejný název, za nějž bude přidáno slovo main (např. definice tříd a funkcí v souboru xyz.cc, hlavičkový soubor xyz.h, hlavní program xyzmain.cc). Program xyzmain.cc však bude sloužit pouze pro vás, cvičící budou vaše třídy a funkce testovat zvlášť vytvořeným programem (program xyzmain.cc přesto pro případnou detailní kontrolu odevzdáte.)

Tyto zásady samozřejmě začněte ve svých programech používat až v okamžiku, kdy výuka postoupí tak daleko, že by vám mělo být jasné, co se jimi míní.