V tomto článku popíši, jak používat kód napsaný v jazyce C a v jazyce C++ v jednom projektu.

Co je potřeba vědět, pokud používáme současně C a C++ kód

Zde jsou některé hlavní body (ačkoli někteří dodavatelé kompilátoru nemusí všechny tyto požadavky vyžadovat; podívejte se do dokumentace vašeho dodavatele kompilátoru):

  • Při kompilaci main() musíte použít kompilátor C++ (např. pro statickou inicializaci).

  • Kompilátor C++ by měl řídit proces sestavení (linkování) (např. aby mohl získat své speciální knihovny).

  • Kompilátory C a C++ pravděpodobně musí pocházet od stejného dodavatele a mít kompatibilní verze (např. aby měly stejné konvence volání).

Kromě toho si budete muset přečíst zbytek této části, abyste zjistili, jak zajistit, aby vaše funkce C byly volatelné pomocí C++ a/nebo vaše funkce C++ byly volatelné pomocí jazyka C.

Mimochodem existuje další způsob, jak celou věc zvládnout: zkompilujte veškerý váš kód (dokonce i váš kód ve stylu C) pomocí kompilátoru C++. To do značné míry eliminuje potřebu míchat C a C++ a navíc to způsobí, že budete opatrnější (a možná – doufejme! – objevíte nějaké chyby) v kódu ve stylu C. Nevýhodou je, že budete muset určitými způsoby aktualizovat svůj kód ve stylu C, v podstatě proto, že kompilátor C++ je opatrnější/vybíravější než kompilátor C, který toho zkousne hodně. Jde o to, že úsilí potřebné k vyčištění kódu ve stylu C může být menší než úsilí potřebné ke smíchání C a C++ a jako bonus získáte vyčištěný kód ve stylu C. Je zřejmé, že nemáte moc na výběr, pokud nemůžete změnit svůj kód ve stylu C (např. pokud je od třetí strany).

Jak volat C funkci z C++?

Je potřeba deklarovat funkci v C jako extern "C" v C++ kódu a můžete ji volat z C nebo z C++. Například:

source.cpp
// C++ kód

extern "C" void f(int); // první způsob

extern "C" {    // druhý způsob
    int g(double);
    double h();
};

void code(int i, double d)
{
    f(i);
    int ii = g(d);
    double dd = h();
    // ...
}

Definice funkce v Céčku může vypadat takto:

source.c
/* C code: */

void f(int i)
{
   /* ... */
}

int g(double d)
{
   /* ... */
}

double h()
{
   /* ... */
}

Je důležité vědět, co se týká typů, že určující jsou C++ pravidla a ne Céčková. Takže nelze volat funkci deklarovanou extern "C" se špatným počtem argumentů. Například toto nebude fungovat:

nefunguje.cpp
// C++ kód

void dalsi_kod(int i, double d)
{
    double dd = h(i,d); // chyba, neočekávané argumenty (funkce h je deklarována bez parametrů)
    // ...
}

Jak volat C++ funkci z Céčka?

Jednoduše, v C++ kódu deklarujte funkci jako extern "C" a můžete ji volat z Céčkového i C++ kódu. Například:

source.cpp
// C++ kód

extern "C" void f(int);

void f(int i)
{
    // ...
}

Nyní můžeme používat funkci f() třeba takto:

volani_f.c
/* Céčkový kód */

void f(int);

void cc(int i)
{
    f(i);
    /* ... */
}

Přirozeně to bude fungovat jenom pro nečlenské funkce (tj. funkce, které nejsou součástí žádné třídy class). Jestliže potřebujete volat některou členskou funkci (včetně virtuálních funkcí) z C, tak potřebujete jednoduchý obal (wrapper). Například:

source2.cpp
// C++ kód

class C {
    // ...
    virtual double f(int);
};

extern "C" double call_C_f(C* p, int i) // obalová funkce (wrapper)
{
    return p->f(i);
}

Nyní může být funkce C::f() použita třeba takto:

source2.c
/* Céčkový kód */

double call_C_f(struct C* p, int i);

void ccc(struct C* p, int i)
{
    double d = call_C_f(p,i);
    /* ... */
}

Když chcete volat přetížené funkce (overloaded functions) z C, tak musíte udělat obaly s různými jmény pro Céčkový kód. Například:

overloaded.cpp
// C++ kód
void f(int);
void f(double);

extern "C" void f_i(int i)    { f(i); }
extern "C" void f_d(double d) { f(d); }

Teď mohou být funkce f() volány takto:

call_overloaded.c
/* Céčkový kód */

void f_i(int);
void f_d(double);

void ccc(int i, double d)
{
    f_i(i);
    f_d(d);
    /* ... */
}
Tato technika může být použita k volání C++ knihovny z Céčkového kódu dokonce i tehdy, pokud nechcete (nebo nemůžete) měnit C++ hlavičkové soubory.

Jak mohu vložit standardní C hlavičkový soubor do C++ kódu?

K vložení #include standardní hlavičky (třeba <cstdio>), nemusíte dělat nic neobvyklého. T.j.

source.cpp
// Toto je C++ kód

#include <cstdio>       // Nic neobvyklého na tomto řádku

int main()
{
    std::printf("Hello world\n"); // Nic neobvyklého při volání
    // ...
}

Část std:: z volání std::printf vypadá neobvykle jenom tehdy, pokud jste Céčkaři, ale je to správný způsob jak programovat v C++.

Pokud kompilujete C kód pomocí C++ překladače, nechcete všechna volání printf() upravovat na std::printf(). Naštěstí v tomto případě pro C kód se bude spíše používat hlavička starého stylu <stdio.h> než hlavičku nového stylu <cstdio> a kouzlo jmenných prostorů se postará o vše ostatní:

Céčkový kód kompilovaný C++ kompilátorem
/* Tohle je C kód, který kompiluji C++ kompilátorem */

#include <stdio.h>  /* nic nového pod sluncem, #include funguje jako v Céčku */

int main()
{
  printf("Nazdar, céčkaři!\n"); /* opět nic neobvyklého, jako v C */
  /* ... */
}
Pokud máte nesystémové Céčkové hlavičkové soubory, postupuje se trochu jinak. Jsou dva případy: buď mohu měnit hlavičkový soubor nebo nemohu měnit hlavičkový soubor.

Jak mohu vkládat nesystémové hlavičkové C soubory do mého C++ kódu

Pokud vkládáme Céčkový hlavičkový soubor, který není poskytován systémem, možná budeme muset zabalit řádek #include do konstrukce extern "C" { /…​/ }. To říká kompilátoru C++, že funkce deklarované v záhlaví souboru jsou funkce C.

// Toto je C++ kód

extern "C" {
  // vložíme deklaraci funkce f(int i, char c, float x)
#include "my-C-code.h"
}

int main()
{
  f(7, 'x', 3.14);   // Poznámka: nic neobvyklého v tomto volání
  // ...
}

Jak upravit vlastní C hlavičkové soubory, aby se snadno vkládaly do C++ kódu

Když vkládáme hlavičkový soubor C, který není poskytován systémem, a pokud jsme schopni změnit hlavičku C, měli bychom silně zvážit přidání extern "C" {…​} do hlavičky, tak ji upravíme pro snadné vkládání do C++ kódu. Protože kompilátor jazyka C nebude rozumět konstrukci extern "C", musíme řádky extern "C" { a } zabalit do #ifdef __cplusplus, aby je kompilátory jazyka C neviděly.

Krok č. 1: Umístěte následující řádky na začátek vašeho hlavičkového souboru C (poznámka: symbol __cplusplus je definován jenom pokud zdrojový kód kompilujeme kompilátorem C++):

#ifdef __cplusplus
extern "C" {
#endif

Krok č.2 Na konec C hlavičkového souboru dáme ukončující složenou závorku tímto způsobem:

#ifdef __cplusplus
}
#endif

Teď můžeme vkládat Céčkové hlavičky bez extern "C" a bude to fungovat:

// C++ kód

// vkládáme deklaraci funkce f(int i, char c, float x)
#include "my-C-code.h"   // nic neobvyklého, funguje to

int main()
{
  f(7, 'x', 3.14);       // poznámka: funguje to
  // ...
}

Zdroje a odkazy