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

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ů

14.11.2017 16:56 /František Kučera
Máš rád svobodný software a hardware nebo se o nich chceš něco dozvědět? Zajímá tě DIY, CNC, SDR nebo morseovka? Přijď na sraz spolku OpenAlt – tradičně první čtvrtek před třetím pátkem v měsíci: 16. listopadu od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5).
Přidat komentář

12.11.2017 11:06 /Redakce Linuxsoft.cz
PR: 4. ročník odborné IT konference na téma Datová centra pro business proběhne již ve čtvrtek 23. listopadu 2017 v konferenčním centru Vavruška, v paláci Charitas, Karlovo náměstí 5, Praha 2 (u metra Karlovo náměstí) od 9:00. Konference o návrhu, budování, správě a efektivním využívání datových center nabídne odpovědi na aktuální a často řešené otázky, např Jaké jsou aktuální trendy v oblasti datových center a jak je využít pro vlastní prospěch? Jak zajistit pro firmu či jinou organizaci odpovídající služby datových center? Podle jakých kritérií vybrat dodavatele služeb? Jak volit součásti infrastruktury při budování či rozšiřování vlastního datového centra? Jak efektivně spravovat datové centrum? Jak eliminovat možná rizika? apod.
Přidat komentář

13.9.2017 8:00 /František Kučera
Máš rád svobodný software a hardware nebo se o nich chceš něco dozvědět? Zajímá tě DIY, CNC, SDR nebo morseovka? Přijď na sraz spolku OpenAlt – tentokrát netradičně v pondělí: 18. září od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5).
Přidat komentář

3.9.2017 20:45 /Redakce Linuxsoft.cz
PR: Dne 21. září 2017 proběhne v Praze konference "Mobilní řešení pro business". Hlavní tématy konference budou: nejnovější trendy v oblasti mobilních řešení pro firmy, efektivní využití mobilních zařízení, bezpečnostní rizika a řešení pro jejich omezení, správa mobilních zařízení ve firmách a další.
Přidat komentář

15.5.2017 23:50 /František Kučera
Máš rád svobodný software a hardware nebo se o nich chceš něco dozvědět? Zajímá tě DIY, CNC, SDR nebo morseovka? Přijď na sraz spolku OpenAlt, který se bude konat ve čtvrtek 18. května od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5).
Přidat komentář

12.5.2017 16:42 /Honza Javorek
PyCon CZ, česká konference o programovacím jazyce Python, se po dvou úspěšných ročnících v Brně bude letos konat v Praze, a to 8. až 10. června. Na konferenci letos zavítá např. i Armin Ronacher, známý především jako autor frameworku Flask, šablon Jinja2/Twig, a dalších projektů. Těšit se můžete na přednášky o datové analytice, tvorbě webu, testování, tvorbě API, učení a mentorování programování, přednášky o rozvoji komunity, o použití Pythonu ve vědě nebo k ovládání nejrůznějších zařízení (MicroPython). Na vlastní prsty si můžete na workshopech vyzkoušet postavit Pythonem ovládaného robota, naučit se učit šestileté děti programovat, efektivně testovat nebo si v Pythonu pohrát s kartografickým materiálem. Kupujte lístky, dokud jsou.
Přidat komentář

2.5.2017 9:20 /Eva Rázgová
Putovní konference československé Drupal komunity "DrupalCamp Československo" se tentokrát koná 27. 5.2017 na VUT FIT v Brně. Můžete načerpat a vyměnit si zkušenosti z oblasti Drupalu 7 a 8, UX, SEO, managementu týmového vývoje, využití Dockeru pro Drupal a dalších. Vítáni jsou nováčci i experti. Akci pořádají Slovenská Drupal Asociácia a česká Asociace pro Drupal. Registrace na webu .
Přidat komentář

1.5.2017 20:31 /Pavel `Goldenfish' Kysilka
PR: 25.5.2017 proběhne v Praze konference na téma Firemní informační systémy. Hlavními tématy jsou: Informační systémy s vlastní inteligencí, efektivní práce s dokumenty, mobilní přístup k datům nebo využívání cloudu.
Přidat komentář

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

> Poslední diskuze

15.12.2017 15:11 / Petit
freehold nj

15.12.2017 15:06 / Petit
nj freehold

5.12.2017 11:50 / Thomas
kitchen renovations

18.9.2017 14:37 / Rojas
high security vault

15.9.2017 7:33 / Wilson
new zealand childcare jobs

Více ...

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