2
votes

#pragma une fois vs inclure des gardes

Je suis en train de passer par Contrôle de comportement défini par l'implémentation

et il y a le texte suivant en relation avec #pragma once :

Contrairement aux protections d'en-tête, ce pragma rend impossible l'utilisation erronée du même nom de macro dans plus d'un fichier.

Je ne suis pas sûr de ce que cela implique. Quelqu'un peut-il expliquer?

TIA


4 commentaires

Cela implique que vous pouvez utiliser la même macro comme garde dans différents fichiers par erreur


Notez que #pragma once a des failles qui peuvent être exposées par une structure de projet modérément compliquée.


@ user4581301 - en effet. C’est pourquoi #pragma once ne fait pas partie du C standard ou du C ++ standard.


Vous voudrez peut-être vous pencher sur cette question: stackoverflow.com/ questions / 1143936 /…


3 Réponses :


7
votes

Exemple :

// /usr/include/lib.h
#pragma once
struct foo{};


// src/ext/lib.h
#pragma once
struct foo{};


// src/headerA.h
#pragma once
#include <lib.h>

// src/headerB.h
#pragma once
#include "ext/lib.h"

// src/file.cpp
#include "headerA.h"
#include "headerB.h" // oops, lib.h is include twice
foo f;

Les macros de garde d'en-tête nécessitent un effort méticuleux pour les garder uniques. #pragma once fait cela automatiquement.

Pour être honnête et pour être complet, permettez-moi de mentionner l'inconvénient (également dans la page liée): #pragma once ne reconnaît pas le même fichier s'il est inclus à partir de plusieurs chemins. Cela peut être un problème pour les projets avec une structure de fichiers exotique. Exemple:

// src/featureA/thingy.h
#ifndef HEADER_GUARD_FOR_THINGY
#define HEADER_GUARD_FOR_THINGY
struct foo{};
#endif


// src/featureB/thingy.h
#ifndef HEADER_GUARD_FOR_THINGY
#define HEADER_GUARD_FOR_THINGY
struct bar{};
#endif


// src/file.cpp
#include "featureA/thingy.h"
#include "featureB/thingy.h" // oops, this file is removed by header guard
foo f;
bar b;


2 commentaires

Bien que tout cela soit correct, cela ne mentionne pas les problèmes rencontrés par #pragma once qui n'existent pas avec les gardes d'inclusion.


@PeteBecker ce n'est pas ce qui a été demandé. Mais je l'ai maintenant ajouté par souci d'exhaustivité.



2
votes

Disons que vous avez un fichier d'en-tête, File1.h. Vous avez créé File1.h avec:

#pragma once 

Il n'y a rien dans la langue pour empêcher d'autres fichiers d'en-tête d'utiliser la même macro, FILE_1_H , comme include gardes. p>

  1. Un fichier d'en-tête dans une bibliothèque que vous utilisez aurait pu définir cela.
  2. Vous pouvez utiliser les mêmes protections d'en-tête dans File2.h dans votre propre base de code en raison d'une erreur de copier-coller.

Lorsque cela se produit, un seul des fichiers .h peut être #include d dans un fichier .cpp. Dans le meilleur des cas, vous obtiendrez des erreurs de compilation qui permettront de résoudre le problème. Dans le pire des cas, vous finirez par utiliser le mauvais type ou la mauvaise fonction et le problème se manifestera au moment de l'exécution.

Pour ces raisons, les protections d'inclusion ne sont pas robustes et sujettes à des erreurs de l'utilisateur.

Cependant, si votre compilateur le prend en charge et que vous utilisez

#pragma once

dans tous vos fichiers d'en-tête, de telles erreurs seront évitées.


Veuillez noter que l'utilisation de

#ifndef FILE_1_H
#define FILE_1_H

// Contents of File1.h

#endif

a ses propres inconvénients. Pour en savoir plus, consultez ce qui suit:

Est #pragma autrefois un garde d'inclusion sûr?
Quels sont les dangers d'utiliser #pragma une fois? p>


2 commentaires

Bien que tout cela soit correct, cela ne mentionne pas les problèmes rencontrés par #pragma once qui n'existent pas avec les gardes d'inclusion.


@PeteBecker, c'est vrai. Elle est cependant orthogonale à la question du PO.



1
votes

Inclure les gardes ressemblent à ceci:

#ifndef SOME_NAME
#define SOME_NAME

// The header file contents

#endif

Bien qu'il y ait des conventions de dénomination, il n'y a rien pour imposer ce que la macro ( SOME_NAME dans ce cas) sera réellement appelée . Si vous essayez d'inclure deux fichiers d'en-tête qui utilisent le même nom de macro, le compilateur ne verra pas le contenu du deuxième fichier car #ifndef ___ de ce fichier échouera (la macro était déjà définie dans le premier fichier).

Ce problème n'existe pas avec #pragma once .


4 commentaires

Bien que tout cela soit correct, cela ne mentionne pas les problèmes rencontrés par #pragma once qui n'existent pas avec les gardes d'inclusion.


@PeteBecker Je répondais à la question dans l'OP, qui était une explication de la citation.


Oui, mais vous n’avez pas mentionné que la citation est trompeuse.


@PeteBecker Je ne vois pas en quoi c'est trompeur. Cela explique un inconvénient des protections d'en-tête que #pragma once n'a pas. La phrase suivante de la citation explique les inconvénients de #pragma once : "D'un autre côté, puisque avec #pragma once les fichiers sont exclus en fonction de leur système de fichiers- identité de niveau, cela ne peut pas empêcher d'inclure un en-tête deux fois s'il existe à plus d'un emplacement dans un projet. "