LINUXSOFT.cz Přeskoč levou lištu
Uživatel: Heslo:  
   CZUKPL

> C/C++ (33) - Rozdíly mezi C a C++

Dnes probereme další drobné rozdíly mezi C a C++, napíšeme program který odpovídá normám obou jazyků, ale v každém dělá něco jiného. Povíme si také, proč je třeba někdy kombinovat C s C++, jaké problémy při tom vznikají a jak se dají jednoduše vyřešit.

1.2.2006 06:00 | Jan Němec | Články autora | přečteno 28608×

Drobné nekompatibility

Minule jsme si ukazovali, že C++ není jen rozšířením jazyka C, ale že má také některá omezení. Situace je ovšem ještě o něco komplikovanější. S trochou znalostí můžeme napsat kód, který vyhovuje normám obou jazyků, ale v každém z nich dělá něco jiného.

Makro __cplusplus

Především C++ definuje makro __cplusplus, pomocí podmíněného překladu tak můžeme napsat dvojí kód. Později si ukážeme, že se toho hodně využívá v knihovnách s rozhraním pro oba jazyky se společnými hlavičkovými soubory. Právě #ifdef __cplusplus je ten správný postup, pokud potřebujeme detekovat C++.

Znaková konstanta

V C mají znakové konstanty typ int, v C++ char.

Prostor jmen struktur

Již z minula víme, že v C mají struktury vlastní prostor jmen a v C++ nikoli. Díky překrývání globálních identifikátorů lokálními a operátoru sizeof  tak lze vykouzlit kód, který v obou jazycích dělá něco jiného.

Níže uvedený kód berte jako odstrašující případ, nikoli jako návod pro vlastní programování.

#include <stdio.h>

int x;

int main(void) {
  struct x {
    int i, j;
  };

  /* V C++ je definováno makro __cplusplus. */
  puts("Test 1");
#ifdef __cplusplus
  puts("C++");
#else
  puts("C");
#endif
 
  /* V C++ je znaková konstanta char, v C int. */
  puts("Test 2");
  if (sizeof('A') == sizeof(char)) {
    puts("C++");
  } else {
    puts("C");
  }

  /* V C++ nemají struktury vlastní prostor jmen, lokální definice struktury
     tak zastíní globální definici proměnné se stejným názvem. */
  puts("Test 3");
  if (sizeof(x) != sizeof(int)) {
    puts("C++");
  } else {
    puts("C");
  }

 return 0;
}

Mezi oběma jazyky existují další drobné odlišnosti, které mohou programátora potrápit.

void funkce()

Zápis funkce s prázdnými závorkami v hlavičce znamená v C funkci, o jejíchž parametrech nic nevíme. V C++ jde o funkci bez parametrů. Nejlepší je asi psát v obou jazycích

void funkce(void)

v tomto případě jde vždy o funkci bez parametrů.

Různé typy char

C++ zná a rozlišuje 3 různé typu odvozené od char: char, unsigned char a signed char. Později si ukážeme, že je to důležité například pro přetížené funkce.

Typ bool

V C++ je typ bool, který je určen pro logické hodnoty. Tento typ také vrací příslušné operátory (&&, || a podobně), zatímco v C je návratovým typem int.

Konstanty

C sice zná modifikátor const, ale například

const int sedm = 7;

je ve skutečnosti jen definice proměnné, která má své umístění v paměti, pouze nelze její hodnotu standardními prostředky měnit. V C++ se jedná opravdu o konstantu, která nemusí být linkována a může dokonce nahradit symbolické konstanty preprocesoru například při definici mezí polí a podobně.

const int sedm = 7;

int pole[sedm];

Odlišnosti při linkování

Jak již víme, v C i C++ se jednotlivé zdrojové soubory překládají na objektové (zpravidla mají jméno *.o nebo *.obj na Windows). Spustitelný program se slinkuje z přeloženého kódu v objektových souborech a statických knihovnách. V C jednoznačně identifikuje funkci (která není static) nebo globální proměnnou na úrovni přeloženého kódu její jméno z kódu zdrojového. Bohužel v C++ to takhle jednoduše nejde. Díky přetěžování funkcí, metodám tříd a prostorům jmen může existovat ve zdrojovém kódu více funkcí se stejným identifikátorem. V přeloženém kódu je ovšem duplicita nepřípustná, překladač proto musí název rozšířit o nějaký řetězec odvozený od prostoru jmen, případné třídy a typu parametrů.

Zkuste přeložit (ale nelinkovat) následující kód

void funkce(void) {}
void funkce(int i, const char *str) {}

jako C++

g++ priklad.cpp -c -o cpp.o

a potom jako C.

gcc priklad.c -c -o c.o

V případě C to udělejte dvakrát a vždy jednu z funkcí zakomentujte, jinak dojde ke konfliktu identifikátorů.

Podívejte se nějakým textovým prohlížečem, úplně stačí vim, na soubory c.o (obě verze) a cpp.o. V případě C naleznete v obou případech na konci souboru symbol funkce, zatímco C++ generuje názvy jako _Z6funkcev a _Z6funkceiPKc. Zakomponování typu parametrů je docela názorné.

Linkování C s C++

Z uvedených rozdílů v přeloženém kódu vyplývají určité komplikace při spojování modulů napsaných v C s těmi v C++. Jde přitom o běžnou situaci, například každá linuxová distribuce obsahuje obrovské množství přeložených knihoven, statických i dynamických, řada z nich je určena pro oba jazyky a až na výjimky existují v jediné společné variantě tj. nikoli přeložená zvlášť pro C a zvlášť pro C++. Programátor, který je používá se přitom (obvykle) nemusí o nic starat. Jak je to možné?

Kdyby se ani programátor knihovny v C o nic nestaral a aplikační programátor v C++ použil funkci z knihovny, skončí překlad programu chybou linkeru, který by například místo symbolu funkce hledal v knihovně třeba symbol _Z6funkceiPKc. Naštěstí jazyk C++ obsahuje modifikátor funkce, který změní její linkování ve stylu C

extern "C" void funkce(int i, const char *str) {
  /* ... */
}

nebo alternativně pro více funkcí najednou.

extern "C" {
  void funkce1(int i, const char *str) {
    /* ... */
  }

  void funkce2(int i, const char *str) {
    /* ... */
  }
  /* ... */
}

Totéž se uvádí i v hlavičkovém souboru knihovny.

extern "C" void funkce(int i, const char *str);

Pokud tedy chceme nějakou knihovnu používat z obou jazyků, používáme standard volání funkcí ve stylu C. Věc je však ještě o trochu komplikovanější, neboť konstrukci extern "C" lze přeložit pouze v C++, takže například v hlavičkovém souboru knihovny je třeba použít podmíněný překlad.

Ukážeme si to na příkladu, napíšeme si knihovnu a program, který ji využívá. Nebude přitom záležet na jazyku programu a navíc ani na jazyku knihovny, všechny 4 kombinace C a C++ budou fungovat.

Knihovna

Knihovna poskytuje jedinou funkci, která vrací název jazyka, v němž je přeložená. Zdrojový kód tvoří soubory knihovna.h a knihovna.c respektive .cpp. Začneme hlavičkovým souborem.

/* knihovna.h */
#ifndef knihovnaH
#define knihovnaH

/* Makro CFUNKCE se rozvine na extern "C" v C++ nebo na prázdný řetězec v C. */

#ifdef __cplusplus
#define CFUNKCE extern "C"
#else
#define CFUNKCE
#endif

CFUNKCE const char * jazykKnihovny(void);
#endif

Implementace funkce jazykKnihovny je jednoduchá.

/* knihovna.c nebo .cpp */
#include "knihovna.h"

CFUNKCE const char * jazykKnihovny(void) {
#ifdef __cplusplus
  return "C++";
#else
  return "C";
#endif
}

Hlavní program

Program jen vypíše svůj jazyk a pomocí funkce jazykKnihovny rovněž jazyk, kterým byla přeložena knihovna.

/*program.c nebo .cpp */
#include <stdio.h>
#include "knihovna.h"

const char * jazykProgramu(void) {
#ifdef __cplusplus
  return "C++";
#else
  return "C";
#endif
}

int main(void) {
  printf("Kód v %s volá funkci knihovny v %s.\n", jazykProgramu(),
    jazykKnihovny());
  return 0;
}

Všimněte si, že hlavní program je velmi jednoduchý a že aplikační programátor ani nemusí znát rozdíly v linkování mezi C a C++, konstrukci extern "C" a nemusí rovněž vědět, v jakém jazyku je knihovna implementována a jakým způsobem se linkují funkce rozhraní knihovny.

Na překlad a spuštění všech čtyř variant bude asi nejlepší si napsat malý skript.

#/bin/sh

gcc knihovna.c -c
gcc program.c -c
gcc program.o knihovna.o -o program
./program

gcc knihovna.c -c
g++ program.cpp -c
g++ program.o knihovna.o -o program
./program

g++ knihovna.cpp -c
gcc program.c -c
g++ program.o knihovna.o -o program
./program

g++ knihovna.cpp -c
g++ program.cpp -c
g++ program.o knihovna.o -o program
./program

Zbývá už jen se pokochat výsledkem:

[honza@localhost]$ chmod 744 skript
[honza@localhost]$ ./skript
Kód v C volá funkci knihovny v C.
Kód v C++ volá funkci knihovny v C.
Kód v C volá funkci knihovny v C++.
Kód v C++ volá funkci knihovny v C++.
[honza@localhost]$

Pokračování příště

Drobných rozdílů mezi C a C++ jsme si už užili víc než dost. Od příštího dílu se budeme zabývat tím, co je v C++ navíc.

Verze pro tisk

pridej.cz

 

DISKUZE

Nejsou žádné diskuzní příspěvky u dané položky.



Příspívat do diskuze mohou pouze registrovaní uživatelé.
> Vyhledávání software
> Vyhledávání článků

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

15.4.2017 15:20 /František Kučera
Máš rád svobodný software a hardware nebo se o nich chceš něco dozvědět? Zajímá tě IoT a radiokomunikace? Přijď na sraz spolku OpenAlt, který se bude konat ve středu 19. dubna od 18:30 v Šenkovně (Sokolská 60, Praha 2).
Přidat komentář

5.3.2017 19:12 /Redakce Linuxsoft.cz
PR: 23. března proběhne v Praze konferenci na téma Cloud computing v praxi. Hlavními tématy jsou: Nejžhavější trendy v oblasti cloudu a cloudových řešení, Moderní cloudové služby, Infrastruktura současných cloudů, Efektivní využití cloudu, Nástrahy cloudových řešení a jak se jim vyhnout.
Přidat komentář

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

> Poslední diskuze

18.9.2017 14:37 / Rojas
high security vault

15.9.2017 7:33 / Wilson
new zealand childcare jobs

31.8.2017 12:11 / Jaromir Obr
Re: ukůládání dat ze souboru

30.7.2017 11:12 / Jaromir Obr
Národní znaky

27.7.2017 12:24 / Jaromir Obr
Cteni/zapis

Více ...

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