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 21244×

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ů

12.8.2018 16:58 /František Kučera
Srpnový pražský sraz spolku OpenAlt se koná ve čtvrtek – 16. 8. 2018 od 19:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát jsou tématem srazu databáze prezentaci svého projektu si pro nás připravil Standa Dzik. Dále bude prostor, abychom probrali nápady na využití IoT a sítě The Things Network, případně další témata.
Přidat komentář

16.7.2018 1:05 /František Kučera
Červencový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 19. 7. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát bude přednáška na téma: automatizační nástroj Ansible, kterou si připravil Martin Vicián.
Přidat komentář

18.6.2018 0:43 /František Kučera
Červnový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 21. 6. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát na téma: F-Droid, aneb svobodný software do vašeho mobilu. Kromě toho budou k vidění i vývojové desky HiFive1 se svobodným/otevřeným čipem RISC-V.
Přidat komentář

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ář

   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