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:
// 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:
/* 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:
// 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:
// C++ kód
extern "C" void f(int);
void f(int i)
{
// ...
}
Nyní můžeme používat funkci f() třeba takto:
/* 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:
// 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:
/* 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:
// 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:
/* 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.
// 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í:
/* 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
// ...
}