web-dev-qa-db-fra.com

Est-ce que #pragma est une fois un coffre-fort inclut un gardien?

J'ai lu qu'il y a une optimisation du compilateur lors de l'utilisation de #pragma once qui peut permettre une compilation plus rapide. Je reconnais que cela n’est pas standard et que cela pourrait donc poser un problème de compatibilité entre plates-formes.

Est-ce quelque chose qui est supporté par la plupart des compilateurs modernes sur des plateformes autres que Windows (gcc)?

Je veux éviter les problèmes de compilation de la plate-forme, mais aussi le travail supplémentaire des gardes de secours:

#pragma once
#ifndef HEADER_H
#define HEADER_H

...

#endif // HEADER_H

Devrais-je être concerné? Devrais-je dépenser plus d'énergie mentale à ce sujet?

256
Ryan Emerle

Utiliser #pragma once devrait fonctionner sur n'importe quel compilateur moderne, mais je ne vois aucune raison de ne pas utiliser un #ifndef include include standard. Cela fonctionne très bien. Le seul inconvénient est que GCC ne supportait pas #pragma once avant version 3.4 .

J'ai également constaté que, du moins sur GCC, il reconnaît le #ifndef standard include garde et l'optimise , il ne devrait donc pas être beaucoup plus lent que #pragma once.

157
Zifre

#pragma once a un inconvénient (autre que d'être non standard): si vous avez le même fichier à des emplacements différents (nous l'avons parce que notre système de compilation copie des fichiers), le compilateur pensera qu'il s'agit de fichiers différents.

305
Motti

Je souhaite que #pragma once (ou quelque chose du genre) soit dans la norme. Inclure les gardes n'est pas un gros problème (mais ils semblent un peu difficiles à expliquer aux personnes qui apprennent la langue), mais cela semble être une gêne mineure qui aurait pu être évitée.

En fait, depuis 99,98% du temps, le comportement #pragma once est le comportement souhaité, cela aurait été agréable si d'empêcher l'inclusion multiple d'un en-tête était automatiquement gérée par le compilateur, avec un #pragma ou quelque chose permettant le double inclus.

Mais nous avons ce que nous avons (sauf que vous pourriez ne pas avoir #pragma once).

53
Michael Burr

Je ne connais aucun avantage en termes de performances, mais cela fonctionne certainement. Je l'utilise dans tous mes projets C++ (bien sûr, j'utilise le compilateur MS). Je trouve cela plus efficace que d'utiliser

#ifndef HEADERNAME_H
#define HEADERNAME_H
...
#endif

Il fait le même travail et ne remplit pas le préprocesseur avec des macros supplémentaires. 

GCC supporte #pragma once officiellement à partir de la version 3.4 .

32
JaredPar

GCC supporte #pragma once depuis 3.4, voir http://en.wikipedia.org/wiki/Pragma_once pour un support supplémentaire pour le compilateur.

Le gros avantage que je vois sur l'utilisation de #pragma once au lieu d'inclure des gardes est d'éviter les erreurs de copier/coller.

Regardons les choses en face: la plupart d’entre nous commençons à peine un nouveau fichier d’en-tête à partir de rien, mais simplement copiez un fichier existant et le modifiez à nos besoins. Il est beaucoup plus facile de créer un modèle de travail en utilisant #pragma once au lieu d’inclure des gardes. Moins je modifie le modèle, moins je risque de rencontrer des erreurs. Avoir la même garde dans différents fichiers entraîne d'étranges erreurs de compilation et il faut un certain temps pour comprendre ce qui ne va pas.

TL; DR: #pragma once est plus facile à utiliser.

21
uceumern

Utiliser '#pragma once' peut n'avoir aucun effet (il n'est pas supporté partout - bien que cela soit de plus en plus largement supporté), vous devez donc utiliser le code de compilation conditionnel de toute façon. Dans ce cas, pourquoi se préoccuper de '#pragma once'? Le compilateur l’optimise probablement quand même. Cela dépend toutefois de vos plates-formes cibles. Si toutes vos cibles le supportent, alors utilisez-le - mais cela devrait être une décision consciente, parce que tout l'enfer se déchaînera si vous utilisez uniquement le pragma, puis le portez vers un compilateur qui ne le prend pas en charge.

11
Jonathan Leffler

Je l'utilise et j'en suis content, car je dois taper beaucoup moins pour créer un nouvel en-tête. Cela a bien fonctionné pour moi sur trois plates-formes: Windows, Mac et Linux. 

Je n'ai pas d'informations sur les performances, mais je pense que la différence entre #pragma et la protection include ne sera en rien comparable à la lenteur de l'analyse syntaxique de la grammaire C++. C'est le vrai problème. Essayez de compiler le même nombre de fichiers et de lignes avec un compilateur C #, par exemple, pour voir la différence.

En fin de compte, utiliser la garde ou le pragma n'aura aucune importance.

11
Edwin Jarvis

Pas toujours.

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52566 a un bel exemple de deux fichiers destinés à être inclus, mais pensés à tort comme identiques en raison d'horodatages et de contenu identiques (non nom de fichier identique).

5
Omer

L'avantage en termes de performances est de ne pas avoir à rouvrir le fichier une fois que le #pragma a été lu une fois. Avec les gardes, le compilateur doit ouvrir le fichier (qui peut être coûteux en temps) pour obtenir les informations qu’il ne devrait pas inclure à nouveau dans son contenu.

Cela n’est que théorique car certains compilateurs n’ouvrent pas automatiquement les fichiers ne contenant aucun code lu, pour chaque unité de compilation.

Quoi qu'il en soit, ce n'est pas le cas de tous les compilateurs, donc, idéalement, évitez #pragma une fois pour tout code multi-plateforme car il n'est pas du tout standard/n'a pas de définition ni d'effet standardisés. Cependant, pratiquement, c'est vraiment mieux que des gardes.

En fin de compte, la suggestion mieux que vous pouvez obtenir pour être sûr d'obtenir la meilleure vitesse de votre compilateur sans avoir à vérifier le comportement de chaque compilateur dans ce cas, consiste à utiliser pragma une fois et gardes.

#ifndef NR_TEST_H
#define NR_TEST_H
#pragma once

#include "Thing.h"

namespace MyApp
{
 // ...
}

#endif

De cette façon, vous obtenez le meilleur des deux (multiplate-forme et rapidité de compilation). 

Comme c’est plus long à taper, j’utilise personnellement un outil pour aider à générer tout cela de manière très simple (Visual Assist X).

4
Klaim

En utilisant gcc 3.4 et 4.1 sur de très grands arbres (en utilisant parfois distcc ), je n’ai encore vu aucune accélération lorsqu’on utilise #pragma une fois au lieu de, ou en combinaison avec les gardes include classiques.

Je ne vois vraiment pas en quoi cela vaut la peine de confondre les anciennes versions de gcc, ou même d'autres compilateurs, car il n'y a pas de réelle économie. Je n'ai pas essayé tous les différents détartreurs, mais je suis prêt à parier que cela déroutera beaucoup d'entre eux.

Je souhaite moi aussi que le projet ait été adopté de bonne heure, mais je peux voir l’argument "Pourquoi avons-nous besoin de cela lorsque ifndef fonctionne parfaitement?". Compte tenu des nombreux recoins sombres et complexités de C, inclure des gardes est l’une des choses les plus faciles à expliquer. Si vous avez un minimum de connaissances sur le fonctionnement du préprocesseur, il devrait être explicite. 

Si vous constatez une accélération significative, veuillez toutefois mettre à jour votre question.

2
Tim Post

La principale différence est que le compilateur a dû ouvrir le fichier d'en-tête pour lire l'inclusion. En comparaison, une fois de plus, pragma oblige le compilateur à garder une trace du fichier et à ne créer aucun fichier IO lorsqu'il rencontre une autre inclusion pour le même fichier. Bien que cela puisse sembler négligeable, cela peut facilement évoluer avec d’énormes projets, en particulier ceux qui n’ont pas une bonne tête incluent des disciplines.

Cela dit, les compilateurs actuels (y compris GCC) sont suffisamment intelligents pour traiter des gardes comme Pragma une fois. c'est-à-dire qu'ils n'ouvrent pas le fichier et évitent la pénalité du fichier IO.

Dans les compilateurs qui ne supportent pas pragma, j’ai vu des implémentations manuelles un peu lourdes.

#ifdef FOO_H
#include "foo.h"
#endif

Personnellement, j’aime bien l’approche #pragma une fois, car elle évite les complications liées aux conflits de noms et aux fautes de frappe. C'est aussi un code plus élégant en comparaison. Cela dit, pour le code portable, cela ne devrait pas faire de mal d'avoir les deux à moins que le compilateur ne s'en plaint.

2
Shammi

Aujourd'hui, la vieille école comprend des gardes sont aussi rapides qu'une fois. Même si le compilateur ne les traite pas spécialement, il s'arrête quand il voit #ifndef WHATEVER et WHATEVER est défini. Ouvrir un fichier est très bon marché aujourd'hui. Même s'il devait y avoir une amélioration, ce serait de l'ordre de quelques millisecondes.

Je n'utilise tout simplement pas une seule fois #pragma, car cela ne présente aucun avantage. Pour éviter les conflits avec d'autres gardes d'inclusion, j'utilise quelque chose comme: CI_APP_MODULE_FILE_H -> CI = Initiales de la société; APP = nom de l'application; Le reste est explicite.

2
CMircea

Si nous utilisons msvc ou Qt (jusqu'à Qt 4.5), puisque GCC (jusqu'à 3.4), msvc prennent tous les deux en charge #pragma once, je ne vois aucune raison de ne pas utiliser #pragma once.

Le nom du fichier source correspond généralement au même nom de classe et nous savons que parfois, nous avons besoin du refactor pour renommer le nom de la classe, puis nous avons dû changer le #include XXXX aussi, donc je pense que la maintenance manuelle du #include xxxxx n’est pas un travail intelligent. même avec l'extension Visual Assist X, la maintenance de "xxxx" n'est pas un travail nécessaire.

1
raidsan

Remarque supplémentaire à l’intention des personnes qui pensent qu’une inclusion unique et ponctuelle de fichiers d’en-tête est toujours souhaitée: je construis des générateurs de code utilisant l’inclusion double ou multiple de fichiers d’en-tête depuis des décennies. Surtout pour la génération de stubs de bibliothèques de protocoles, je trouve très confortable d'avoir un générateur de code extrêmement portable et puissant, sans outils ni langages supplémentaires. Je ne suis pas le seul développeur à utiliser ce schéma en tant que cela blogue X-Macros show. Cela ne serait pas possible sans la protection automatique manquante.

0
Marcel