C/C++: Comment utiliser le do-while(0); construire sans les avertissements du compilateur comme C4127?
Je suis souvent utiliser do-while(0) construire dans mon #définit, pour les raisons décrites dans cette réponse. Aussi, je suis en train d'utiliser aussi haut que possible le niveau d'avertissement du compilateur pour attraper plus de potentiel problème et rendre mon code plus robuste et multi-plateforme. Donc, je suis généralement à l'aide de -Wall
avec gcc et /Wall
avec MSVC.
Malheureusement MSVC se plaindre do-while(0) construire:
foo.c(36) : warning C4127: conditional expression is constant
Que dois-je faire à propos de cet avertissement?
Juste désactiver globalement pour tous les fichiers? Il ne semble pas être une bonne idée pour moi.
- Puisque vous avez ajouté le C++ tag, est-il possible de convertir le
#define
des macros dans les fonctions inline? Ce serait plus sûr. - J'ai aussi ajouté C tag, alors j'ai pensé que je lui ai demandé à propos de C-une solution compatible. Dois-je enlever C++ tag alors?
- Avez-vous essayé un état comme la sizeof(char) != 1...?
- Depuis les langues et les solutions sont très différents, oui. Supprimer la balise de langue que vous ne voulez pas de réponses pour
Vous devez vous connecter pour publier un commentaire.
Résumé: Cet avertissement (C4127) dans ce cas particulier, est un subtil compilateur bug. Hésitez pas à le désactiver.
En profondeur:
Il a pour but de repérer les situations lors de la logique de l'expression prend la valeur d'une constante dans la non-évidence les situations (comme,
if(a==a && a!=a)
, et en quelque sorte, il s'est tournéwhile(true)
et d'autres constructions dans invalide.Microsoft recommande l'utilisation de
for(;;)
pour boucle infinie si vous voulez avoir cet avertissement, et il n'y a pas de solution pour votre cas. C'est l'un des très peu de Niveau 4 avertissements de ma société de développement de conventions permettent à désactiver.__pragma
solution à l'échelle mondiale de désactiver un avertissement.if (1) {stuff;} else
sans un point-virgule de fin sur l'autre? Ou peut-êtredo { stuff; if (always_true_condition) break; } while(1)
? Certainementdo ... while(1)
boucles internesbreak
oureturn
déclarations sont assez communs, comme le sontif
états avec des conditions constantes.Peut-être que votre code doit plus chouettes:
Ou les moins photogéniques, mais aussi moins d'avertissement de production:
do {} while( (void)0, 0)
stuff()
?Comme Michael Burr noté dans Carl Smotricz' réponse, pour Visual Studio 2008+ vous pouvez utiliser __pragma:
Vous pouvez le mettre sur une seule ligne (sans les
\
s) si vous préférez utiliser des macros pour être illisible.while (0)
si vous voulez continuer à traiter les problèmes dans lef
etg
consolidés. Voir d'autres MULTI_LINE_MACRO réponse pour quelque chose de vaguement réutilisables.J'ai un modèle que j'ai basé sur une réponse ici & il fonctionne sur clang, gcc & MSVC. Je poste ici dans l'espoir qu'il sera utile pour les autres & parce que les réponses ici m'a aidé à formuler.
Et je l'utilise comme ceci:
Vous pouvez l'utiliser dans les macros trop:
Cela fonctionne aussi pour le cas indiqué ci-dessus, si F utilise 'une FOIS' dans une fonction:
Edit: des Années plus tard, je me rends compte que j'ai oublié d'ajouter le modèle que j'ai réellement écrit cette macro pour - le "switch-comme-un-rendez-vous" modèle:
Cela vous donne un try/finally-ish construction qui est plus structuré qu'un crufty goto à votre nettoyage & code de retour. En utilisant cette FOIS la macro au lieu de tout(0) s'VS en place.
Utilisant les nouvelles versions de MS compilateur, vous pouvez utiliser d'avertissement de suppression:
Vous pouvez également pousser/désactiver/pop, mais supprimer est beaucoup plus pratique mécanisme.
Ce compilateur bug a été corrigé dans Visual Studio 2015 mise à Jour de 1, même si le releases notes ne le mentionnez pas.
Le bug a été expliqué dans l'une des précédentes réponses si:
Voici une autre approche possible, ce qui évite C4127, C4548 et C6319 (VS2013 d'analyse de code d'avertissement), et ne nécessite pas de macros ou des pragmas:
Cela permet d'optimiser loin, et compile sans mise en garde dans GCC 4.9.2 et VS2013. Dans la pratique, il pourrait aller dans un espace de noms.
L'avertissement est due à la
while(false)
. Cette site donne un exemple de la façon de contourner ce problème. Exemple de site (vous devrez à nouveau travailler pour votre code):Il suffit d'insérer votre code entre le début et la FIN.
Vous pouvez utiliser
Et plus tôt définir
WHILE_FALSE
macro comme suit:Vérifié sur MSVC++2013.
Cette "while(0)" s'étoffe d'un hack et vient de tourner autour de vous mordre.
Est-ce que votre compilateur offre
#pragma
s sélective et localement la désactivation des messages d'erreur? Si oui, ce pourrait être une bonne alternative.__pragma()
préprocesseur de l'opérateur, qui, malheureusement, est légèrement différente de C99 de_Pragma()
opérateur (C99 prendre un littéral de chaîne, MSVC s prend des jetons qui ne sont pas dans une chaîne de caractères): msdn.microsoft.com/en-us/library/d9x1s805.aspx#define STUFF for (bool b = true; b;) do {f(); g(); b = false;} while (b)
?#define STUFF for (;;) {f(); g(); break;}
?Vous pouvez utiliser l'opérateur virgule au lieu de do-while(0) construire pour le multi-déclaration de macro pour être utilisées dans les expressions. Ainsi, au lieu de:
Utilisation:
Cela fonctionne de manière indépendante de la plate-forme et permet d'éviter d'avertissement du compilateur (même si plus haut niveau d'avertissement est activée).
Notez que dans virgules contenant la macro (deuxième FOO) le résultat de la dernière instruction (Statement3) serait le résultat de la macro.
Je dois dire, j'ai jamais pris la peine avec le do..while construire dans les macros. Tout le code dans mes macros est lui-même inclus dans des accolades, mais sans la faire-..alors que. Par exemple:
Aussi, mon propre norme de codage (et de la pratique informelle depuis des années) a été de faire de tous les blocs, où qu'ils se produisent être entourés d'accolades, qui a également plus ou moins supprime le problème.
Il y a une solution, mais il va ajouter plus de cycles à votre code. N'utilisez pas de valeur explicite dans la condition du while.
Vous pouvez le faire comme ceci:
fichier1.h
la variable I_am_a_zero devraient être définies dans certains .c fichier.
De toute façon cet avertissement ne s'affiche pas dans GCC 🙂
Voir ce une question relative à la.
Vous pouvez utiliser #pragma warning pour:
(vous avez besoin d'un # devant les pragmas, mais c'est aussi un moment difficile de traiter avec eux et de mise en forme en même temps)
Vous voulez push/pop les mises en garde, plutôt que de désactiver/activer parce que vous ne voulez pas interférer avec les arguments de ligne de commande qui peut être choisi de façon à transformer les avertissements sur/off (quelqu'un peut utiliser la ligne de commande pour désactiver l'avertissement, vous ne voulez pas forcer sur le dos... le code ci-dessus traite de la).
C'est mieux que de tourner l'avertissement off à l'échelle mondiale puisque vous pouvez contrôler seulement la partie que vous voulez. Vous pouvez également faire une partie de la macro.
#define foo(x) \
j'ai l'erreur: erreur C2162: attendu macro paramètre formelBien, pour moi, les ouvrages suivants, sans le C4127 avertissement:
Bien sûr, les compilateurs sont intelligents et zzsome ne devrait pas être une constante
Cela va désactiver l'avertissement et le compilateur va encore être en mesure d'optimiser le code:
J'ai trouvé ceci pour être la version la plus courte
N'ai pas vérifié pour voir si il est optimisé par le compilateur, mais je suppose qu'il est.
} while ([]() { return 0; }());
Vous pouvez utiliser
for
boucle tant que:Macro:
J'utiliserais
C'est l'équivalent de
et rendements pas de mises en garde.
do { } while(0)
note le manque de semi colon, est utilisé dans les macros pour une raison