388 votes

Combinant C++ et C - Comment #ifdef __cplusplus fonctionne ?

Je suis en train de travailler sur un projet qui a beaucoup de l'héritage du code C. Nous avons commencé à écrire en C++, avec l'intention d'éventuellement convertir le code héritage, ainsi. Je suis un peu confus sur la façon dont le C et le C++ interagir. Je comprends qu'en enveloppant le code C extern "C" le compilateur C++ ne sera pas mangle le code C de noms, mais je ne suis pas entièrement sûr de savoir comment le mettre en œuvre.

Donc, en haut de chaque fichier en-tête C (après l'inclure des gardes), nous avons

#ifdef __cplusplus
extern "C" {
#endif

et au fond, nous écrire

#ifdef __cplusplus
}
#endif

Entre les deux, nous avons tous nos comprend, typedefs, et des prototypes de fonction. J'ai quelques questions, pour voir si je suis à la compréhension de cette correctement:

  1. Si j'ai un fichier C++ A. hh qui inclut un fichier en-tête C B. h, comprend un autre fichier en-tête C C. h, comment cela fonctionne? Je pense que lorsque le compilateur étapes dans B. h, __cplusplus seront définies, de sorte qu'il se terminera avec le code extern "C" (et __cplusplus ne sera pas définie à l'intérieur de ce bloc). Donc, quand il marche dans C. h, __cplusplus ne sera pas défini et le code ne sera pas enveloppé dans extern "C". Est-ce correct?

  2. Est-il quelque chose de mal avec envelopper un morceau de code avec extern "C" { extern "C" { .. } }? Ce sera la deuxième extern "C" faire?

  3. Nous n'avons pas mis ce wrapper autour de la .c fichiers, faites-le .h fichiers. Donc, ce qui se passe si une fonction n'a pas un prototype? Le compilateur pense que c'est une fonction C++?

  4. Nous sommes également à l'aide de certains tiers le code qui est écrit en C, et ne pas cette sorte de wrapper autour de c'. Chaque fois que j'inclure un en-tête à partir de cette bibliothèque, j'ai été de mettre un extern "C" autour de #include. Est-ce la bonne façon de traiter avec qui?

  5. Enfin, il a créé une bonne idée? Est-il autre chose que nous devrions faire? Nous allons être un mélange de C et de C++ pour l'avenir prévisible, et je voulez vous assurer que nous allons couvrir tous les nos bases.

349voto

Andrew Shelansky Points 1401

extern "C" n'a pas vraiment changer la façon dont le compilateur lit le code. Si votre code est dans une .c fichier, il sera compilé comme le C, si elle est dans un .fichier cpp, il sera compilé comme le C++ (sauf si vous faites quelque chose d'étrange à votre configuration).

Ce extern "C" n'est affecter la liaison. Les fonctions C++, lors de la compilation, ont leurs noms déformés -- c'est ce qui rend la surcharge possible. Le nom de la fonction se modifie en fonction du type et du nombre de paramètres, de sorte que les deux fonctions avec le même nom seront différents noms de symbole.

Code à l'intérieur d'un extern "C" est encore de code C++. Il y a des limites à ce que vous pouvez faire dans une extern "C" bloc, mais ils sont tous sur la liaison. Vous ne pouvez pas définir de nouveaux symboles qui ne peuvent pas être construit avec une liaison C. Cela signifie pas de classes ou de modèles, par exemple.

extern "C" blocs nid bien. Il y a aussi extern "C++" si vous trouvez vous-même désespérément coincé à l'intérieur de l' extern "C" des régions, mais ce n'est pas une bonne idée d'un point de vue de la propreté.

Maintenant, spécialement en ce qui concerne vos questions numérotées:

Sujet n ° 1: __cplusplus doit être définie à l'intérieur d' extern "C" blocs. Cela n'a pas d'importance, cependant, puisque les blocs devraient nid proprement.

Sujet n ° 2: __cplusplus sera défini pour toute unité de compilation qui est en cours d'exécution à travers le compilateur C++. Généralement, cela signifie que .rpc fichiers et les fichiers inclus par qui .fichier cpp. La même .h (ou .hh ou .php ou quoi avez-vous) pourrait être interprété comme C ou C++ à des époques différentes, si différentes unités de compilation. Si vous voulez des prototypes dans la .h fichier pour le consulter C noms de symbole, il doit avoir extern "C" lors être interprété comme C++, et ils ne devraient pas avoir extern "C" lors être interprété comme C -- d'où l' #ifdef __cplusplus vérification.

Pour répondre à votre question #3: les fonctions sans les prototypes ont C++ de couplage si elles sont dans .fichiers cpp et non à l'intérieur d'un extern "C" bloc. C'est bien, quoique, parce que si elle n'a pas de prototype, il ne peut être appelé par d'autres fonctions dans le même fichier, et ensuite, vous n'avez généralement pas attention à ce que le lien ressemble, parce que vous ne prévoyez pas sur d'avoir cette fonction sera appelée par quelque chose d'extérieur à la même unité de compilation, de toute façon.

Pour le #4, vous avez exactement. Si vous êtes incluant un en-tête pour le code qui a une liaison C (telles que le code qui a été compilé par un compilateur C), alors vous devez extern "C" l'en-tête -- de cette façon vous serez en mesure de lien avec la bibliothèque. (Sinon, votre linker être à la recherche pour les fonctions avec des noms comme _Z1hic quand vous étaient à la recherche d' void h(int, char)

5: Ce type de mélange est une commune de la raison de l'utilisation d' extern "C", et je ne vois rien de mal avec cette façon de faire -- assurez-vous de comprendre ce que vous faites.

53voto

Anthony Williams Points 28904
  1. extern "C" ne change pas la présence ou l'absence de l' __cplusplus macro. Il change juste le lien et le nom du modificateur de la enveloppé déclarations.

  2. Vous pouvez imbriquer extern "C" blocs tout à fait heureux.

  3. Si vous compilateur de votre .c fichiers C++ puis ce qui n'est pas dans un extern "C" bloc, et sans un extern "C" prototype sera traitée comme une fonction C++. Si vous compilez comme C puis, bien sûr, tout sera une fonction C.

  4. Oui

  5. Vous pouvez sans risque de mélange de C et de C++ de cette façon.

25voto

Andy Dent Points 9852

Un couple de pièges qui sont colloraries Andrew Shelansky excellente réponse et pas d'accord un peu avec n'a pas vraiment changer la façon dont le compilateur lit le code

Parce que votre prototypes de fonction sont compilés comme le C, vous ne pouvez pas avoir une surcharge de même les noms de fonction avec des paramètres différents - c'est l'une des principales caractéristiques de l'amputation des noms du compilateur. Il est décrit comme un lien de la question, mais qui n'est pas tout à fait vrai - vous obtiendrez des erreurs à partir du compilateur et de l'éditeur de liens.

Les erreurs du compilateur passera si vous essayez d'utiliser le C++ dispose de prototype déclaration telles que la surcharge.

L'éditeur de liens erreurs se produisent plus tard, parce que votre fonction ne semble pas être trouvé, si vous ne pas avoir la extern "C" wrapper autour de déclarations et de l'en-tête est inclus dans un mélange de C et de C++.

L'une des raisons pour décourager les gens d'utiliser le compiler en C comme en C++ paramètre est parce que cela signifie que leur code source n'est plus portable. Ce paramètre est un paramètre de projet et donc, si un .c fichier est supprimé dans un autre projet, il ne sera pas compilé comme le c++. Je préfère les gens prennent le temps de renommer le fichier des suffixes .rpc.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X