LINUXSOFT.cz Přeskoč levou lištu

ARCHIV



   

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

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ů

28.11.2018 23:56 /František Kučera
Prosincový sraz spolku OpenAlt se koná ve středu 5.12.2018 od 16:00 na adrese Zikova 1903/4, Praha 6. Tentokrát navštívíme organizaci CESNET. Na programu jsou dvě přednášky: Distribuované úložiště Ceph (Michal Strnad) a Plně šifrovaný disk na moderním systému (Ondřej Caletka). Následně se přesuneme do některé z nedalekých restaurací, kde budeme pokračovat v diskusi.
Komentářů: 1

12.11.2018 21:28 /Redakce Linuxsoft.cz
22. listopadu 2018 se koná v Praze na Karlově náměstí již pátý ročník konference s tématem Datová centra pro business, která nabídne odpovědi na aktuální a často řešené otázky: Jaké jsou aktuální trendy v oblasti datových center a jak je optimálně využít pro vlastní prospěch? Jak si zajistit odpovídající služby datových center? Podle jakých kritérií vybírat dodavatele služeb? Jak volit vhodné součásti infrastruktury při budování či rozšiřování vlastního datového centra? Jak efektivně datové centrum spravovat? Jak co nejlépe eliminovat možná rizika? apod. Příznivci LinuxSoftu mohou při registraci uplatnit kód LIN350, který jim přinese zvýhodněné vstupné s 50% slevou.
Přidat komentář

6.11.2018 2:04 /František Kučera
Říjnový pražský sraz spolku OpenAlt se koná v listopadu – již tento čtvrtek – 8. 11. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma umění a technologie, IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář

4.10.2018 21:30 /Ondřej Čečák
LinuxDays 2018 již tento víkend, registrace je otevřená.
Přidat komentář

18.9.2018 23:30 /František Kučera
Zářijový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 20. 9. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář

9.9.2018 14:15 /Redakce Linuxsoft.cz
20.9.2018 proběhne v pražském Kongresovém centru Vavruška konference Mobilní řešení pro business. Návštěvníci si vyslechnou mimo jiné přednášky na témata: Nejdůležitější aktuální trendy v oblasti mobilních technologií, správa a zabezpečení mobilních zařízení ve firmách, jak mobilně přistupovat k informačnímu systému firmy, kdy se vyplatí používat odolná mobilní zařízení nebo jak zabezpečit mobilní komunikaci.
Přidat komentář

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

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

> Poslední diskuze

31.7.2023 14:13 / Linda Graham
iPhone Services

30.11.2022 9:32 / Kyle McDermott
Hosting download unavailable

13.12.2018 10:57 / Jan Mareš
Re: zavináč

2.12.2018 23:56 / František Kučera
Sraz

5.10.2018 17:12 / Jakub Kuljovsky
Re: Jaký kurz a software by jste doporučili pro začínajcího kodéra?

Více ...

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