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 24662×
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
|
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 ...
|