web-dev-qa-db-fra.com

Protecteurs d'en-tête en C ++ et C

À LearnCpp.com | 1.10 - Un premier aperçu du préprocesseur . Sous Protecteurs d'en-tête , il y a ces extraits de code:

add.h:

#include "mymath.h"
int add(int x, int y);

soustraire.h:

#include "mymath.h"
int subtract(int x, int y);

main.cpp:

#include "add.h"
#include "subtract.h"

Lors de la mise en œuvre du protège-en-tête , il est mentionné comme suit:

#ifndef ADD_H
#define ADD_H

// your declarations here

#endif
  • Quelle pourrait être la déclaration ici? Et, int main() devrait-il venir après #endif?
  • L'ajout de _H Est-il une convention ou une chose incontournable?

Merci.

30
Simplicity

Le FILENAME_H Est une convention. Si vous le vouliez vraiment, vous pourriez utiliser #ifndef FLUFFY_KITTENS Comme protection d'en-tête (à condition qu'il ne soit défini nulle part ailleurs), mais ce serait un bug délicat si vous le définissiez ailleurs, disons comme le nombre de chatons pour quelque chose ou autre.

Dans le fichier d'en-tête add.h, les déclarations sont littéralement entre #ifndef Et #endif.

#ifndef ADD_H
#define ADD_H

#include "mymath.h"
int add(int x, int y);

#endif

Enfin, int main() ne devrait pas être dans un fichier d'en-tête. Il doit toujours être dans un fichier .cpp.

Pour éclaircir:

#ifndef ADD_H Signifie essentiellement "si ADD_H n'a pas été #defined Dans le fichier ou dans un fichier inclus, alors compilez le code entre les directives #ifndef Et #endif". Donc, si vous essayez de #include "add.h" Plus d'une fois dans un fichier .cpp, Le compilateur verra ce qu'ADD_H était déjà #defined Et ignorera le code entre #ifndef et #endif. Les protections d'en-tête empêchent uniquement qu'un fichier d'en-tête soit inclus plusieurs fois dans le même fichier .cpp. Les protections d'en-tête n'empêchent pas les autres fichiers .cpp D'inclure le fichier d'en-tête. Mais tous les fichiers .cpp Peuvent inclure le fichier d'en-tête gardé ne seule fois.

55
The Communist Duck
  • Le résultat du prétraitement d'un fichier d'implémentation (".cpp") est une unité de traduction (TU).

  • Les en-têtes peuvent inclure d'autres en-têtes, de sorte qu'un en-tête peut être indirectement inclus plusieurs fois dans la même UT. (Votre mymath.h en est un exemple.)

  • Les définitions ne peuvent avoir lieu qu'au plus une fois par UT. (Certaines définitions ne doivent pas non plus figurer dans plusieurs UT; ce cas est légèrement différent et n'est pas traité ici.)

  • Le problème que les gardes résolvent empêche plusieurs erreurs de définition lorsqu'un en-tête donné est inclus plus d'une fois dans une UT.

  • Les gardes d'inclusion fonctionnent en "enveloppant" le contenu de l'en-tête de telle sorte que le second et les suivants incluent ne soient pas des opérations. Les directives # ifndef/# define devraient être les deux premières lignes du fichier, et #endif devrait être la dernière.

  • Les protections incluses ne sont utilisées que dans les en-têtes. Ne définissez pas votre fonction principale dans un en-tête: placez-la dans un fichier d'implémentation.

Si vous avez un en-tête qui définira un type et déclarera une fonction, mais a également besoin d'un en-tête lui-même:

#include "other_header.h"

struct Example {};

void f();

"Envelopper" avec des gardes d'inclusion donne le contenu complet du fichier:

#ifndef UNIQUE_NAME_HERE
#define UNIQUE_NAME_HERE

#include "other_header.h"

struct Example {};

void f();

#endif

Le nom utilisé pour la garde d'inclusion doit être unique, sinon des noms contradictoires donneront des résultats confus. Ces noms ne sont que de simples macros, et il n'y a rien dans la langue qui impose un certain style. Cependant, les conventions de projet imposent généralement des exigences. Il existe plusieurs styles de nommage de garde différents que vous pouvez trouver ici sur SO et ailleurs; cette réponse donne de bons critères et une bonne vue d'ensemble.

17
Fred Nurk

Tout ce que les protecteurs d'en-tête font est de ne permettre à vos en-têtes d'être inclus qu'une seule fois. (S'ils sont inclus plusieurs fois, ils sont ignorés.)

Le nom que vous utilisez n'a pas d'importance, mais il est classique d'utiliser le nom de fichier en majuscules, y compris l'extension comme vous l'avez démontré.

Votre main devrait vraiment être dans un .cpp fichier, mais si vous le mettez dans un en-tête, placez-le à l'intérieur des gardes afin qu'il ne soit pas déclaré plusieurs fois.

3
Mehrdad

Non, l'int principal () va dans un .cpp. Les déclarations sont les autres choses que vous alliez mettre dans l'en-tête. _H est une convention, vous pouvez voir diverses conventions de protection d'en-tête.

1
Puppy

Je déclare une déclaration dans le fichier d'en-tête et les définitions ou int main() entre source.cpp fichier.

_H est là simplement pour indiquer que quelqu'un va inclure des fichiers d'en-tête en utilisant des gardes d'inclusion.

Si vous utilisez MSVC++, vous pouvez également utiliser #pragma once

1
cpx