LINUXSOFT.cz Přeskoč levou lištu
Uživatel: Heslo:  
   CZUKPL

> C/C++ (32) - Omezení C++ oproti C

Jazyk C++ není jen rozšířením C, přináší i některá omezení a drobné nekompatibility. Nejdůležitější omezení si dnes projdeme a ukážeme si, že rozumně napsaný kód v C bude fungovat i jako C++.

23.1.2006 06:00 | Jan Němec | Články autora | přečteno 21095×

Drobná omezení C++

Restrikcí je v C++ oproti C celá řada, ale zpravidla se nejedná o podstatné záležitosti a v některých případech je pro plné pochopení rozdílu jazyků zapotřebí poměrně pokročilá znalost příslušných norem. Navíc téměř vždy kód, který lze přeložit pouze jako C nebo má dokonce v obou jazycích jiný význam, odporuje zásadám správného programování v C, i když je třeba v souladu s normou jazyka.

Nová klíčová slova

C++ obsahuje celou řadu nových klíčových slov, které pochopitelně nemůžeme použít jako identifikátory. Následující definice je sice korektní v C, ale v C++ neprojde překladem, neboť class je zde klíčové slovo.

int class = 1; 

Přísnější typová kontrola

V C++ neprojdou některé implicitní konverze, například mezi ukazateli různých typů

int *pi;

pi = malloc(sizeof(int));

a je třeba explicitně přetypovávat. Přísnější pravidla se týkají především ukazatelů, ale změny jsou i u přetypování intu na výčtový typ a podobně.

int *pi;

pi = (int *) malloc(sizeof(int));

Návratová hodnota funkcí

Funkce, která formálně podle hlavičky vrací hodnotu nějakého typu různého od void, ji musí vracet i fakticky.

int funkce() {
}

Jedná se o užitečnou kontrolu běžné programátorské chyby - zapomenutého returnu. V poměrně vzácných případech funkcí, které nikdy nekončí standardním způsobem (například zavolají exit, exec, nekonečnou smyčku a podobně) nebo nás jejich návratová hodnota nezajímá, ale přesto mají z nějakého důvodu v hlavičce uvedený neprázdný návratový typ, tak musíme zavolat return.

Prototyp funkcí

Původní verze C se chovaly vůči parametrům funkcí trochu jako asembler. Volající kód prostě uložil na zásobník nějaké parametry a jejich počet a typ plně závisel na rozhodnutí programátora. Kód funkce pak definoval parametry podobně jako lokální proměnné a bylo jen na programátorovi, zda se předané a vybrané parametry typem, počtem a pořadím shodují. Díky tomu překladač nepotřeboval znát v místě volání hlavičku funkce. Uvedený postup například umožňuje dávat funkcím přebytečné parametry, které nevyužijí, a jistě i některé mnohem nebezpečnější věci od nepřenositelného kódu až po vyložené chyby. Na dalším vývoji jazyka C je vidět snaha tato pravidla zpřísnit a neumožnit zde přílišnou a nebezpečnou volnost, ale teprve C++ řeší problém definitivně. Překladač musí znát v místě volání prototyp funkce a ta musí být zavolána přesně podle hlavičky. (Situaci v C++ trochu komplikují implicitní konverze, implicitní parametry a přetěžování funkcí, nicméně na úrovni přeloženého kódu to na celé věci nic nemění.) Stará definice podle původní normy C K & R je v C++ zakázána.

Návratová hodnota

Funkce musí vždy explicitně uvádět návratový typ a tento typ nesmí být deklarován přímo v hlavičce funkce. Možná vás to překvapí, ale C by mělo umožnit (ale v praxi často neumožňuje) například zápis

struct s {int i;} f(void) {
 /* ... */ 
}

Funkce main

Funkce main nesmí být rekurzivní a nelze získat její adresu.

Předběžná definice

C umožňuje opakovaně předběžně definovat globální (ale již nikoli lokální) proměnnou i bez klíčového slova extern, pouze jednou však smí být v definici inicializována. Jedná se pochopitelně o jedinou proměnnou, i když je definována vícekrát. V C++ je to zakázané.

int i;
int i;
int i = 1;

int main(void) {
  return 0;
}

I v C++ je samozřejmě možné nejprve deklarovat proměnnou (typicky v hlavičkovém souboru) pomocí extern a to klidně i vícekrát, ale definována bez extern smí být pouze jednou. Tento postup se dnes považuje za standardní v obou jazycích.

Skok přes lokální definici

V C++ je zakázáno přeskočit například pomocí goto nebo break ve switch lokální definici proměnné. Standard C++ totiž umožňuje (a překladač C často toleruje) definici lokální proměnné mimo začátek bloku tj. až po nějakém příkazu. V C++ má každý typ formálně nějaký konstruktor (i když třeba prázdný) a překladač jej proto nedovolí přeskočit, výjimkou je pouze přeskočení celého bloku. Jedná se o poměrně otravné omezení, které je navíc u typů bez faktického konstruktoru zcela zbytečné.

switch (i) {
  case 0:
    int j;
    /* Proveď něco */
    break;
  case 1:
   /* Proveď něco jiného */
    break;
}

Nejjednodušší zpravidla bývá kus kódu s definicí proměnné zabalit do bloku.

switch (i) {
  case 0: {
     int j;
     /* Proveď něco */
   }
   break;
  case 1:
   /* Proveď něco jiného*/
    break;
}

Samozřejmě programátor by měl v podobných případech zvážit, zda není lepší kód rozčlenit a například pro každou case větev definovat funkci.

String o jedničku menší

C umožňuje definovat řetězec o jedničku menší než je jeho inicializace, pokud ji počítáme i s ukončovací nulou. V C++ to neprojde.

char str[3] = "C++";

puts(str);

Spoléhat se však na to, že překladač C za řetězec umístí znak '\0', by bylo dosti riskantní, například moje gcc 4.0.1 to tak neudělá. Funkce puts v uvedeném příkladu tak nejspíše vypíše za řetězcem ještě kus paměti až po nejbližší nulu, případně program spadne.

Otevřené pole

C umožňuje použít ve struktuře pole bez uvedené velikosti, C++ to zakazuje.

struct T {
  int i;
  char s[];
};

V tomto případě však gcc nepotvrdilo moje teoretické znalosti a příklad jsem přeložil i jako C++.

Kompatibilita struktur

V C jsou do určité míry (například pro přiřazení) zaměnitelné dvě na dvou místech stejným způsobem definované struktury, v C++ nikoli, zde se jedná o 2 různé typy. Moje pokusy s gcc (bez ohledu na jazyk a přepínače určující normu) ovšem skončily chybou při překladu.

Dalším podstatným rozdílem je prostor jmen struktur a typů. Z nějakých (poměrně nepochopitelných) důvodů C zavádí místo jediného hned dva různé pojmy: typ a struktura. Tím pádem lze v C pomocí nejrůznějších kombinací klíčových slov struct a typedef a definice proměnné hned několika způsoby zavést proměnnou strukturovaného typu. Jméno typu a jméno struktury jsou přitom dvě různé věci, navíc existují pro obojí dva odlišné prostory jmen. Lze tedy pojmenovat strukturu stejně jako nějaký (třeba zcela nesouvisející) typ. V C++ lze jméno struktury použít, jako by to byl typ, a samostatný prostor jmen struktur zde neexistuje. Díky tomu může dojít při překladu C kódu pomocí překladače C++ ke konfliktu identifikátorů.

typedef int signed32;
struct signed32 {
  int i;
};

Uvedené definice typů by asi žádný rozumný programátor nenapsal. Hodilo by se však pojmenovat nějaký konkrétní typ a odpovídající strukturu stejně. To naštěstí možné je i v C++.

/* Projde v C i v C++. */
typedef struct T {
  int i;
  int j;
} T;

C dokonce umožňuje v rámci struktury definovat proměnnou, která má jméno stejné jako nějaký typ definovaný pomocí typedef. C++ to jednoznačně zakazuje.

typedef int signed32;
struct T {
  int signed32;
};

Ukázali jsme si, že i v čistém C lze snadno psát tak, aby výsledný kód odpovídal rovněž normě C++ a to bych také programátorům doporučil. Vede to k větší přenositelnosti a tím i použitelnosti nejen kódu, ale i programátora samotného. Konstrukce, které projdou pouze v C jsou ve většině případů nebezpečné a často naznačují místa možných chyb. Trochu pedantské je snad jen explicitní přetypovávání ukazatelů po malloc, ale v řadě jiných případů odhalí právě silnější typová kontrola C++ nepříjemné chyby již v době překladu.

Domácí úkoly

Ověřte si rozdíly mezi C a C++ uvedené v článku na svých oblíbených překladačích. Při použití nějaké novější verze gcc by mělo vše fungovat tak, jak je v článku popsáno, ale s jinými překladači můžete narazit na odlišnosti.

Vyzkoušejte si na některých příkladech z předchozích dílů tohoto seriálu, zda je možné překládat běžný C kód překladačem C++. Pokud narazíte na problém, napište o něm do diskuse pod článkem.

Pokračování příště

I v příštím dílu nás budou zajímat odlišnosti obou jazyků.

Verze pro tisk

pridej.cz

 

DISKUZE

Pretypovani 23.1.2006 14:25 Oldrich Pikhart




Příspívat do diskuze mohou pouze registrovaní uživatelé.
> Vyhledávání software
> Vyhledávání článků

23.5.2018 20:55 /Ondřej Čečák
Od pátku 25.5. proběhne na Fakultě informačních technologií ČVUT v Praze openSUSE Conference. Můžete se těšit na spostu zajímavých přednášek, workshopů a také na Release Party nového openSUSE leap 15.0. V na stejném místě proběhne v sobotu 26.5. i seminář o bezpečnosti CryptoFest.
Přidat komentář

20.5.2018 17:45 /Redakce Linuxsoft.cz
Ve čtvrtek 31. května 2018 připravuje webový magazín BusinessIT ve spolupráci s Best Online Média s.r.o. pátý ročník odborné konference Firemní informační systémy 2018. Akce proběhne v kongresovém centru Vavruška (palác Charitas), Karlovo náměstí 5, Praha 2 (u metra Karlovo náměstí) od 9:00 hod. dopoledne do cca 15 hod. odpoledne. Konference je zaměřena na efektivní využití firemních informačních systémů a na to, jak plně využít jejich potenciál. Podrobnější informace na webových stránkách konfrence.
Přidat komentář

14.5.2018 7:28 /František Kučera
Květnový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 17. 5. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát na téma: Audio – zvuk v GNU/Linuxu.
Přidat komentář

7.5.2018 16:20 /František Kučera
Na stránkách spolku OpenAlt vyšla fotoreportáž Pražské srazy 2017 dokumentující srazy za uplynulý rok. Květnový pražský sraz na téma audio se bude konat 17. 5. 2018 (místo a čas ještě upřesníme).
Přidat komentář

17.4.2018 0:46 /František Kučera
Dubnový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 19. 4. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tématem tohoto srazu bude OpenStreetMap (OSM) aneb svobodné mapy.
Přidat komentář

16.3.2018 22:01 /František Kučera
Kulatý OpenAlt sraz v Praze oslavíme klasicky: u limonády a piva! Přijďte si posedět, dát si dobré jídlo a vybrat z mnoha piv do restaurace Kulový blesk, který najdete v centru Prahy nedaleko metra I. P. Pavlova na adrese Sokolská 13, Praha 2. Sraz se koná ve čtvrtek 22. března a začínáme v 18:00. Heslo: OpenAlt. Vezměte s sebou svoje hračky! Uvítáme, když si s sebou na sraz vezmete svoje oblíbené hračky. Jestli máte nějaký drobný projekt postavený na Arduinu, nějakou zajímavou elektronickou součástku, či třeba i pěkný úlovek z crowdfundingové akce, neváhejte. Oslníte ostatní a o zábavu bude postaráno.
Přidat komentář

13.2.2018 0:41 /František Kučera
Únorový pražský sraz OpenAltu se koná 15. 2. 2018 a tentokrát se vydáme na návštěvu do jednoho pražského datacentra. Sejdeme se v 17:50 v severovýchodní části nástupiště tramvajové zastávky Koh-I-Noor. Po exkurzi se přesuneme do restaurace U Pštrosa (Moskevská 49), kde probereme tradiční témata (svobodný software a hardware, DIY, CNC, SDR, 3D tisk…) a tentokrát bude k vidění i IoT brána od The Things Network.
Přidat komentář

11.2.2018 23:11 /Petr Ježek
Hledáte lehký a rychlý prolížeč PDF souborů? Pokud vás již omrzelo čekat na načítání stránek či jiné nešvary, zkuste xreader.
Přidat komentář

   Více ...   Přidat zprávičku

> Poslední diskuze

20.2.2018 18:48 / Ivan Majer
portal

20.2.2018 15:57 / Jan Havel
Jak využíváte služby cloudu v podnikání?

16.1.2018 1:08 / Ivan Pittner
verejna ip od o2 ubuntu

15.1.2018 17:26 / Mira Harvalik
Re: Jak udělat HTML/Javascript swiping gallery do mobilu?

30.12.2017 20:16 / Michal Knoll
odmocnina

Více ...

ISSN 1801-3805 | Provozovatel: Pavel Kysilka, IČ: 72868490 (2003-2018) | mail at linuxsoft dot cz | Design: www.megadesign.cz | Textová verze