A C és a C++ programozási nyelvek szorosan kapcsolódnak egymáshoz, de számos jelentős különbség van közöttük. A C++ egy korai, szabványosítás előtti C, az úgynevezett „C osztályokkal” elágazásaként indult, és úgy tervezték, hogy többnyire forrás-és-link kompatibilis legyen a korabeli C fordítóprogramokkal. Emiatt a két nyelv fejlesztőeszközei (például az IDE-k és a fordítóprogramok) gyakran egyetlen termékbe integrálódnak, és a programozó megadhatja a C vagy a C++ nyelvet forrásnyelvként.
A C azonban nem a C++ részhalmaza, és a nemtriviális C programok nem fordulnak le C++ kódként módosítás nélkül. Hasonlóképpen, a C++ számos olyan funkciót vezet be, amelyek nem érhetők el C-ben, és a gyakorlatban szinte az összes C++-ban írt kód nem konform C kód. Ez a cikk azonban azokra a különbségekre összpontosít, amelyek miatt a konform C kód rosszul formált C++ kód, vagy mindkét nyelven konform/jól formált, de C-ben és C++-ban eltérően viselkedik.
Bjarne Stroustrup, a C++ megalkotója azt javasolta, hogy a C és a C++ közötti inkompatibilitásokat a lehető legnagyobb mértékben csökkenteni kell a két nyelv közötti interoperabilitás maximalizálása érdekében. Mások azzal érveltek, hogy mivel a C és a C++ két különböző nyelv, a kompatibilitásuk hasznos, de nem létfontosságú; e tábor szerint az inkompatibilitás csökkentésére irányuló erőfeszítések nem akadályozhatják az egyes nyelvek önálló fejlesztését. Az 1999-es C szabvány (C99) hivatalos indoklása szerint „a C és a C++ közötti legnagyobb közös részhalmaz fenntartásának elvét” támogatták, „miközben fenntartották a köztük lévő különbséget, és lehetővé tették a külön-külön fejlődésüket”, és kijelentették, hogy a szerzők „megelégedtek azzal, hogy a C++ legyen a nagy és ambiciózus nyelv”.Rationale for International Standard—Programming Languages—C , revision 5.10 (April 2003).
A C99 számos kiegészítése nem támogatott a jelenlegi C++ szabványban, vagy ütközik a C++ funkcióival, például a változó hosszúságú tömbökkel, a natív komplex számtípusokkal és a restrict típusminősítővel.A változó hosszúságú tömb olyan tömb adatszerkezet, amelynek hossza nem a fordításkor, hanem futásidőben kerül meghatározásra.Néhány programozási nyelv beépített (primitív) adattípusként biztosít komplex adattípust komplex számok tárolására és aritmetikai műveletekhez.A C programozási nyelvben a restrict egy kulcsszó, amely mutatódeklarációkban használható. Ennek a típusminősítőnek a hozzáadásával a programozó jelezheti a fordítónak, hogy a mutató élettartama alatt más mutató nem lesz használható a rá mutató objektum eléréséhez.A programozási nyelvek kontextusában a típusminősítő arra utasítja a fordítót, hogy a minősített típust speciális módon kezelje. Másrészről a C fokozatosan igyekezett csökkenteni néhány más inkompatibilitást olyan C++ funkciók beépítésével, mint az egysoros megjegyzések //-val és a vegyes deklarációk és kódok a C99-ben, valamint attribútumok, típuskövetkeztetés az auto kulcsszóval és egy nullptr konstans hozzáadása a C23-ban.
C-ben érvényes, de C++-ban nem létező konstrukciók A C++ szigorúbb típusozási szabályokat (a statikus típusrendszer implicit megsértése nélkül) és inicializálási követelményeket (fordítási idejű kikényszerítés, hogy a hatókörön belüli változók inicializálása ne változzon) érvényesít, ("It is invalid to jump past a declaration with explicit or implicit initializer (except across entire block not entered). … With this simple compile-time rule, C++ assures that if an initialized variable is in scope, then it has assuredly been initialized.") mint a C, ezért néhány érvényes C kód érvénytelen a C++-ban. Ezekre az ISO C++ szabvány C.1. függeléke ad magyarázatot.
A C99 és a C11 számos olyan további funkcióval bővült a C nyelvben, amelyek a C++20 verzió óta nem voltak beépítve a standard C++-ba, mint például a komplex számok, a változó hosszúságú tömbök (a komplex számokat és a változó hosszúságú tömböket a C11-ben opcionális bővítményekként jelölték), a rugalmas tömbtagok, a restrict kulcsszó, a tömbparaméter-minősítők és az összetett literálok.
C-ben és C++-ban eltérően viselkedő konstrukciók Van néhány szintaktikai konstrukció, amelyek mind C-ben, mind C++-ban érvényesek, de eltérő eredményeket adnak a két nyelven. A karakter literálok, mint például az 'a', C-ben int típusúak, C++-ban pedig char típusúak, ami azt jelenti, hogy a sizeof 'a' általában eltérő eredményt ad a két nyelven: C++-ban 1 lesz, míg C-ben sizeof(int). Ennek a típuskülönbségnek egy másik következménye, hogy C-ben az 'a' mindig előjeles kifejezés lesz, függetlenül attól, hogy a char előjeles vagy előjel nélküli típus-e, míg C++-ban ez a fordító implementációjára jellemző. A C++ belső linkeket rendel a névtér-hatókörű const változókhoz, kivéve, ha azok explicit módon extern-ként vannak deklarálva, ellentétben a C-vel, ahol az extern az alapértelmezett minden fájl-hatókörű entitáshoz. A gyakorlatban ez nem vezet csendes szemantikai változásokhoz az azonos C és C++ kód között, hanem fordítási idejű vagy linkelési hibához. A C nyelvben az inline függvények használata megköveteli a függvény prototípus-deklarációjának manuális hozzáadását az extern kulcsszó használatával pontosan egy fordítási egységben, hogy biztosítsa a nem inline verziók belinkelését, míg a C++ ezt automatikusan kezeli. Részletesebben, a C kétféle inline függvénydefiníciót különböztet meg: a hagyományos külső definíciókat (ahol az extern kulcsszót explicit módon használják) és az inline definíciókat. A C++ ezzel szemben csak inline definíciókat biztosít inline függvényekhez. A C nyelvben egy inline definíció hasonló egy belső (azaz statikus) definícióhoz, abban az értelemben, hogy ugyanabban a programban létezhet egy külső definícióval és ugyanannak a függvénynek tetszőleges számú belső és inline definíciójával más fordítási egységekben, amelyek mindegyike eltérő lehet. Ez egy független szempont a függvény összekapcsolásától (linkage), de nem független szempont. A C fordítóknak mérlegelési jogkörük van, hogy válasszanak ugyanazon függvény inline és külső definíciói között, ha mindkettő látható. A C++ azonban megköveteli, hogy ha egy külső linkkel rendelkező függvényt beágyazva deklarálunk bármely fordítási egységben, akkor azt minden olyan fordítási egységben deklarálni (és így definiálni is) kell, ahol használják, és hogy az adott függvény összes definíciója azonos legyen, az ODR-t követve. A statikus beágyazott függvények azonosan viselkednek C-ben és C++-ban. Mind a C-nek (C99 óta), mind a C++-nak van egy logikai bool típusa true és false konstansokkal, de ezek eltérően vannak definiálva. A C++-ban a bool egy beépített típus és egy foglalt kulcsszó. ** A C99-ben egy új kulcsszó, a _Bool kerül bevezetésre új Boolean-típusként. Az stdbool.h fejléc a bool, true és false makrókat tartalmazza, amelyek rendre _Bool-ként, 1-ként és 0-ként vannak definiálva. Ezért a true és false értékek int típusúak. A C23-ban viszont a bool (és annak true és false értékei) kulcsszavak. A C++ nyelvben a char8_t, char16_t és char32_t típusokkal lehet egyetlen UTF kódegységet kódolni. A C23 ezeket tartalmazza, de más egész számtípusok typedef-jeként, nem pedig különálló beépített típusokként, így a nevük nem foglalt kulcsszó, hanem a <uchar.h> fájlban. C-ben implementációfüggő, hogy egy int típusú bitmező előjeles vagy előjel nélküli, míg C++-ban mindig előjeles, hogy illeszkedjen az alapul szolgáló típushoz.
Az előző szakasztól való számos egyéb különbség is kihasználható olyan kód létrehozására, amely mindkét nyelven lefordul, de eltérően viselkedik. Például a következő függvény különböző értékeket ad vissza C-ben és C++-ban:
extern int T;
int size(void) { struct T { long i, j; };
return sizeof(T); // C: return sizeof(int) // C++: return sizeof(struct T) }
Ez annak köszönhető, hogy a C nyelv a struktúra cimkék előtt struct-nak kell lennie (így a sizeof(T) a változóra utal), de a C++ nyelvben ez elhagyható (így a sizeof(T) az implicit typedef-re utal). Figyeljünk arra, hogy az eredmény más lesz, ha az extern deklarációt a függvényen belül helyezzük el: ekkor egy azonos nevű azonosító jelenléte a függvény hatókörében megakadályozza, hogy az implicit typedef érvénybe lépjen C++ esetén, és az eredmény C és C++ esetén ugyanaz lesz. Azt is vegyük észre, hogy a fenti példában a kétértelműség a sizeof operátorral használt zárójelből adódik. A sizeof T operátor használata esetén a T egy kifejezés lenne, nem pedig típus, így a példa nem fordulna le C++-ban.
C és C++ kód összekapcsolása Míg a C és a C++ nagyfokú forráskód-kompatibilitást tart fenn, a fordítóprogramjaik által létrehozott objektumfájlokban fontos különbségek lehetnek, amelyek a C és C++ kódok keverésekor jelentkeznek. Nevezetesen: A C fordítók nem úgy nevezik el a mangle szimbólumokat,A fordítóprogramok konstrukciójában a 'name mangling (névmanipuláció vagy névdíszítés) egy olyan technika, amelyet a programozási entitások egyedi neve feloldásának szükségességéből adódó különféle problémák megoldására használnak számos modern programozási nyelvben. mint a C++ fordítók. A fordítóprogramtól és az architektúrától függően előfordulhat, hogy a hívási konvenciók eltérnek a két nyelv között.
Ezen okok miatt ahhoz, hogy egy C++ kód meghívjon egy C foo() függvényt, a C++ kódnak extern "C"-vel kell prototípust létrehoznia a foo() függvényhez. Hasonlóképpen, ahhoz, hogy egy C++ kód meghívjon egy bar() függvényt, a bar() függvényhez tartozó C++ kódot extern "C"-vel kell deklarálni.
A fejlécfájlok C és C++ kompatibilitásának fenntartása érdekében bevett gyakorlat, hogy a deklarációjukat extern "C"-ként adják meg a fejléc hatókörére vonatkozóan:
/* Header file foo.h */ #ifdef __cplusplus extern "C" { #endif
// Any symbol declared here gets C linkage void foo(); int bar(int a, int b);
// If this is a C++ compiler, end C linkage #ifdef __cplusplus } #endif
A C és C++ összekapcsolása és hívási konvenciói közötti különbségek finom következményekkel járhatnak a függvénymutatókat használó kódokra nézve. Egyes fordítóprogramok nem működő kódot hoznak létre, ha egy extern "C"-ként deklarált függvénymutató egy nem extern "C"-ként deklarált C++ függvényre mutat.
Például a következő kód:
void qux(); extern "C" void foo(void (*fp)(void));
void bar() { foo(qux); }
A Sun Microsystems C++ fordítójának használatával ez a következő figyelmeztetést okozhatja:
"test.cpp", line 5: Warning (Anachronism): Formal argument fp of type extern "C" void(*)() in call to foo(extern "C" void(*)()) is being passed void(*)().
Ez azért van, mert a qux() függvényt nem C linkelési és hívási konvenciókkal deklaráljuk, hanem átadjuk a C foo() függvénynek.
Lásd még C programozási nyelv C részhalmaz (C++)
Jegyzetek
Fordítás
Kategória:Informatika Kategória:Programozási nyelvek Kategória:Számítógép-programozás Kategória:C++