C og C++ kompatibilitet

Den aktuelle version af siden er endnu ikke blevet gennemgået af erfarne bidragydere og kan afvige væsentligt fra den version , der blev gennemgået den 3. september 2022; verifikation kræver 1 redigering .

Programmeringssprogene C og C++ er tæt beslægtede, men har betydelige forskelle. C++ blev skabt som en efterkommer af præ-standardiseret C, for det meste kompatibel med det på det tidspunkt på niveau med kildekode og link [1] [2] . Som følge heraf er udviklingsværktøjer til begge sprog (såsom udviklingsmiljøer og compilere ) ofte integreret i ét produkt, hvor programmøren vælger C eller C++ som kildesprog.

C er dog ikke en delmængde af C++ [3] , så ikke-trivielle C-programmer vil ikke kompilere til C++ uden ændringer. C++ introducerer også mange funktioner, der ikke er tilgængelige i C, og i praksis matcher næsten al kode skrevet i C++ ikke C-kode. Denne artikel fokuserer dog på de forskelle, der forårsager, at den tilsvarende C-kode staves forkert ..  dårligt udformet ) kode i C++ eller konform/velformet på begge sprog, men kan opføre sig forskelligt i C og C++ . 

Björn Stroustrup , skaberen af ​​C++, foreslog [4] at inkompatibiliteter mellem C og C++ skulle reduceres så meget som muligt for at sikre maksimal interoperabilitet mellem de to sprog. Andre hævder, at eftersom C og C++ er to forskellige sprog, er kompatibilitet mellem dem nyttig, men ikke afgørende; ifølge dem bør bestræbelser på at reducere uforeneligheder ikke hindre bestræbelserne på at forbedre hvert enkelt sprog individuelt. Atter andre hævder, at næsten alle syntaksfejl, der kan laves i C, er blevet omskrevet i C++ på en sådan måde, at der produceres kompilerbar, men ikke nødvendigvis korrekt, kode [5] . Den officielle begrundelse for 1999 C-standarden ( C99 ) "understøtter princippet om at bevare den største fælles delmængde" mellem C og C++, "samtidig med at forskellene mellem dem bevares og tillade dem at udvikle sig separat", hedder det også, at forfatterne var " glad for, at C++ er blevet et stort og ambitiøst sprog" [6] .

Nogle C99-innovationer understøttes ikke i den nuværende C++-standard eller er i konflikt med visse C++-funktioner, såsom arrays med variabel længde , indbyggede komplekse datatyper og typekvalifikationen restrict . På den anden side har C99 reduceret nogle andre inkompatibiliteter sammenlignet med C89 ved at inkludere C++-funktioner såsom enkeltlinjekommentarer //og erklæring/ kodeblanding [7] .

Konstruktioner tilladt i C, men ikke i C++

C++ håndhæver strengere indtastningsregler (ingen implicitte overtrædelser af det statiske typesystem [1] ) og initialiseringskrav (påtvinget kontrol på kompileringstidspunktet, at variabler i omfang ikke overtrædes initialisering, dvs. det er ikke muligt at vende tilbage til et sted før erklæring med eksplicit eller implicit initialisering, bortset fra blokke, hvor et ikke-kontrolflow ikke kom ind) [8] , og derfor er en eller anden gyldig C-kode ikke tilladt i C++. Begrundelsen for dette er angivet i bilag C.1 til ISO C++-standarden [9] .

C99 og C11 tilføjede flere yderligere funktioner til C, som ikke var inkluderet i standard C++, såsom komplekse tal, arrays med variabel længde (bemærk, at komplekse tal og arrays med variabel længde er markeret som valgfri udvidelser i C11), fleksibelt array-element , restriktionsnøgleordet , matrixparameterkvalifikationer, sammensatte literaler  og udpegede initialiseringsprogrammer .

C++ tilføjer mange ekstra nøgleord for at understøtte de nye funktioner. Dette gør C-kode, der bruger disse nøgleord til identifikatorer, ulovlig i C++. For eksempel denne kode:

struktur skabelon { int ny ; struct skabelon * klasse ; }; er gyldig C-kode, men afvises af C++-kompileren, fordi nøgleordene template, newog er classreserveret.

Konstruktioner, der opfører sig forskelligt i C og C++

Der er flere syntakskonstruktioner, der er gyldige i både C og C++, men som giver forskellige resultater på disse sprog.

  • bogstaver i bogstaver , såsom'a', har en typeinti C og en typechari C++, hvilket betyder, at detsizeof 'a'normalt giver forskellige resultater på de to sprog: i C++ vil det være1, mens det i C vil væresizeof(int). Som en anden konsekvens af denne forskel i typer,'a'vil det i C altid være et signeret udtryk, uanset om det ercharsigneret eller usigneret, mens det i C++ afhænger af den specifikke implementering af compileren . 
  • C++ bruger intern sammenkædning af const-variabler i navnerumsomfang, medmindre de udtrykkeligt er erklæret som extern, i modsætning til C, som externer standarden for alle filomfangede entiteter .  Bemærk, at dette i praksis ikke resulterer i skjulte semantiske ændringer mellem identisk C- og C++-kode, men i stedet vil resultere i en kompilerings- eller linkfejl.
  • I C kræver brugen af ​​inline-funktioner, at funktionsprototypedeklarationen ved hjælp af nøgleordet externmanuelt tilføjes til præcis én oversættelsesenhed for at sikre, at ikke- inlineversionen er linket, mens C++ håndterer dette automatisk. Mere specifikt skelner C mellem to slags inline-funktionsdefinitioner: normale eksterne definitioner (hvor 's' er eksplicit brugt extern) og inline-definitioner. C++ giver på den anden side kun indbyggede definitioner for indbyggede funktioner. I C ligner en inline definition en intern (det vil sige statisk) definition, idet den kan eksistere side om side i det samme program med én ekstern definition og et hvilket som helst antal interne og inline definitioner af den samme funktion i andre oversættelsesenheder, alle som kan afvige. Dette er ikke det samme som funktionskobling , men ikke et helt uafhængigt koncept. C compilere får frihed til at vælge mellem at bruge indbyggede og eksterne definitioner af samme funktion, når begge er tilgængelige. C++ kræver dog, at hvis en eksternt linket funktion er deklareret som inlinei enhver oversættelsesenhed, så skal den også erklæres (og derfor også defineres) i hver oversættelsesenhed, hvor den bruges, og at alle definitioner af denne funktion er identiske i reglen om én definition. Bemærk, at statiske indbyggede funktioner opfører sig på samme måde i C og C++.
  • Både C99 og C++ har en boolsk type bool med konstanter trueog false, men de er defineret forskelligt. I C++ bool er det en indbygget type og et reserveret søgeord . I C99 _Boolintroduceres det nye nøgleord som en ny boolesk type. Overskriften stdbool.hindeholder makroerne bool, trueog false, som er defineret som henholdsvis _Bool, 1og 0. Derfor, trueog falsehar en type inti C.

Nogle af de andre forskelle fra det foregående afsnit kan også bruges til at skabe kode, der kompilerer på begge sprog, men opfører sig forskelligt. For eksempel vil følgende funktion returnere forskellige værdier i C og C++:

ekstern int T ; int størrelse ( ugyldig ) { struct T { int i ; int j ; }; returstørrelse af ( T ); /* C: return sizeof(int) * C++: return sizeof(struct T) */ }

Dette skyldes, at C kræver en structstruktur før tags (og derfor sizeof(T)refererer til en variabel), men C++ tillader, at den udelades (og sizeof(T)refererer derfor til implicit typedef). Husk på, at resultatet er anderledes, når erklæringen externplaceres inde i en funktion: at have en identifikator med samme navn i funktionen forhindrer det implicitte typedeffor C++ i at træde i kraft, og resultatet for C og C++ vil være samme. Bemærk også, at tvetydigheden i eksemplet ovenfor skyldes brugen af ​​parenteser på operatoren sizeof. Når det bruges, sizeof Tville det forventes at Tvære et udtryk, ikke en type, og eksemplet ville derfor ikke kompilere i C++.

Sammenkædning af C- og C++-kode

Mens C og C++ opretholder en høj grad af kildekompatibilitet, kan objektfilerne, der genereres af deres kompilatorer, have vigtige forskelle, der dukker op, når C- og C++-kode blandes. Vigtige funktioner:

  • C-kompilatorer udfører ikke navnemangling -symboler, som C++-kompilere [18] gør .
  • Afhængigt af compileren og arkitekturen kan kaldekonventioner variere mellem sprog.

For at C++-koden kan kalde en C-funktion foo(), skal C++-koden oprette en prototype foo() ved hjælp af extern "C". Tilsvarende, for at C-kode skal kalde en C++-funktion, skal C++- bar()koden for bar()den erklæres med extern "C".

En almindelig praksis i header-filer for at opretholde kompatibilitet med både C og C++ er at inkludere en erklæring med extern "C"for hele omfanget af headeren [19] :

/* Overskriftsfil foo.h */ # ifdef __cplusplus /* Hvis dette er en C++ compiler, skal du bruge linking som i C */ ekstern "C" { # Afslut Hvis /* Disse funktioner har et C-layout */ voidfoo ( ); struct bar { /* ... */ }; # ifdef __cplusplus /* Hvis dette er en C++-compiler, skal du afslutte ved at linke som i C */ } # Afslut Hvis

Forskelle mellem C- og C++-link- og kaldekonventioner kan også have konsekvenser for kode, der bruger funktionsmarkører. Nogle compilere vil bryde kode, hvis funktionsmarkøren, der er erklæret som extern "C", peger på en C++-funktion, der ikke er erklæret som extern "C"[20] .

For eksempel følgende kode:

void min_funktion (); extern "C" void foo ( void ( * fn_ptr )( void )); voidbar ( ) { foo ( min_funktion ); }

C++-kompileren fra Sun Microsystems udsender følgende advarsel:

$ CC - c test . cc "test.cc" , linje 6 : Advarsel ( Anakronisme ) : Formelt argument fn_ptr af typen ekstern "C" void ( * )() i call to foo ( ekstern "C" void ( * )() ) sendes videre ugyldig ( * )().

Dette skyldes, at det my_function()ikke er deklareret ved hjælp af C-link- og kaldekonventionerne, men videregives til en C-funktion foo().

Noter

  1. 1 2 Stroustrup, Bjarne An Overview of the C++ Programming Language in The Handbook of Object Technology (Redaktør: Saba Zamir). CRC Press LLC, Boca Raton. 1999. ISBN 0-8493-3135-8. (PDF) 4. Hentet 12. august 2009. Arkiveret fra originalen 16. august 2012.
  2. B. Stroustrup. C og C++: Søskende. C/C++ brugerjournalen. juli 2002 . Hentet 17. marts 2019. Arkiveret fra originalen 21. december 2018.
  3. Bjarne Stroustrups FAQ - Er C en delmængde af C++? . Hentet 22. september 2019. Arkiveret fra originalen 6. februar 2016.
  4. B. Stroustrup. C og C++: Et tilfælde for kompatibilitet. C/C++ brugerjournalen. august 2002. . Hentet 18. august 2013. Arkiveret fra originalen 22. juli 2012.
  5. se UNIX-HATERS-håndbogen , s.208
  6. Begrundelse for international standard – programmeringssprog – C Arkiveret 6. juni 2016. , revision 5.10 (april 2003).
  7. C Dialektindstillinger - Brug af GNU Compiler Collection (GCC) . gnu.org . Arkiveret fra originalen den 26. marts 2014.
  8. N4659: Arbejdsudkast, standard for programmeringssprog C++ . Arkiveret fra originalen den 7. december 2017. ("Det er ugyldigt at springe forbi en erklæring med eksplicit eller implicit initialisering (undtagen på tværs af hele blokken, der ikke er indtastet). ... Med denne enkle kompileringstidsregel sikrer C++, at hvis en initialiseret variabel er i omfanget, så har den helt sikkert blevet initialiseret.")
  9. N4659: Arbejdsudkast, standard for programmeringssprog C++ . Arkiveret fra originalen den 7. december 2017.
  10. IBM Knowledge Center . ibm.com .
  11. FAQ > Casting malloc - Cprogramming.com . www.cprogramming.com . Arkiveret fra originalen den 5. april 2007.
  12. 4.4a - Eksplicit typekonvertering (casting) (16. april 2015). Arkiveret fra originalen den 25. september 2016.
  13. longjmp - C++ reference . www.cplusplus.com _ Arkiveret fra originalen den 19. maj 2018.
  14. 2011 ISO C udkast til standard . Hentet 28. juli 2022. Arkiveret fra originalen 29. marts 2018.
  15. std::complex - cppreference.com . en.cppreference.com . Arkiveret fra originalen den 15. juli 2017.
  16. Inkompatibilitet mellem ISO C og ISO C++ . Arkiveret fra originalen den 9. april 2006.
  17. Restricted Pointers Arkiveret 6. august 2016. fra brug af GNU Compiler Collection (GCC)
  18. IBM Knowledge Center . ibm.com .
  19. IBM Knowledge Center . ibm.com .
  20. Oracle-dokumentation . docs.sun.com. Hentet 18. august 2013. Arkiveret fra originalen 3. april 2009.

Links