C / C++: Comment utiliser le do-while( 0); construire sans avertissement de compilateur comme le T4127?

je suis souvent utiliser do-while(0) construire dans mon #définit, pour les raisons décrites dans cette réponse . J'essaie aussi d'utiliser un niveau d'avertissement aussi élevé que possible du compilateur pour détecter plus de problèmes potentiels et rendre mon code plus robuste et multiplate-forme. Donc j'utilise typiquement -Wall avec gcc et /Wall avec MSVC.

malheureusement MSVC se plaindre de do-while (0) construire:

foo.c(36) : warning C4127: conditional expression is constant

quoi dois-je faire à propos de cet avertissement?

juste le désactiver globalement pour tous les fichiers? Il ne semble pas être une bonne idée pour moi.

42
demandé sur Community 2009-12-22 16:42:17

20 réponses

résumé: cet avertissement (T4127) dans ce cas particulier est un bogue de compilateur subtil. Hésitez pas à le désactiver.

en profondeur:

il a été conçu pour attraper des situations où l'expression logique évalue à une constante dans des situations non évidentes (telles que, if(a==a && a!=a) , et d'une certaine façon, il a tourné while(true) et d'autres constructions utiles en non valide.

Microsoft recommande d'utiliser for(;;) pour boucle infinie si vous voulez cet avertissement, et il n'y a pas de solution pour votre cas. C'est l'un des rares avertissements de niveau 4 que les conventions de développement de mon entreprise permettent de désactiver.

43
répondu Pavel Radzivilovsky 2014-08-04 07:15:34

peut - être que votre code a besoin d'autres hiboux :

do { stuff(); } while (0,0)

ou moins photogénique mais aussi moins annonciatrice:

do { stuff(); } while ((void)0,0)
26
répondu Eric Seppanen 2017-05-23 11:54:31

Comme Michael Bavure dans Carl Smotricz ' réponse , pour Visual Studio 2008+ vous pouvez utiliser __pragma :

#define MYMACRO(f,g)              \
  __pragma(warning(push))         \
  __pragma(warning(disable:4127)) \
  do { f; g; } while (0)          \
  __pragma(warning(pop))

vous pouvez le mettre sur une ligne (sans les \ s) si vous préférez que les macros soient illisibles.

17
répondu Michel de Ruiter 2017-05-23 12:34:14

j'ai un modèle que j'ai basé sur une réponse ici et il fonctionne sur clang, gcc & MSVC. Je poste ici dans l'espoir qu'il sera utile pour les autres et parce que les réponses ici m'a aidé à formuler.

#ifdef WIN32
#  define ONCE __pragma( warning(push) ) \
               __pragma( warning(disable:4127) ) \
               while( 0 ) \
               __pragma( warning(pop) )
#else
#  define ONCE while( 0 )
#endif

et je l'utilise comme ceci:

do {
   // Some stuff
} ONCE;

vous pouvez l'utiliser dans les macros aussi:

void SomeLogImpl( const char* filename, int line, ... );    

#ifdef NDEBUG
#  define LOG( ... )
#else
#  define LOG( ... ) do { \
      SomeLogImpl( __FILE__, __LINE__, __VA_ARGS__ ); \
   } ONCE
#endif

cela fonctionne aussi pour le cas indiqué ci-dessus, si F utilise 'ONCE' dans une fonction:

#define F( x ) do { f(x); } ONCE
...
if (a==b) F(bar); else someFunc();

Edit: des années plus tard, je me rends compte que j'ai oublié d'ajouter le modèle que j'ai en fait écrit cette macro pour-le" switch-like-a-goto "modèle:

do {
    begin_some_operation();

    if( something_is_wrong ) {
        break;
    }

    continue_big_operation();

    if( another_failure_cond ) {
        break;
    }

    finish_big_operation();
    return SUCCESS;
} ONCE;

cleanup_the_mess();
return FAILURE;

cela vous donne une construction try/finally-ish qui est plus structurée qu'un Goto crufty à votre code de nettoyage et de retour. En utilisant cette macro ONCE au lieu de while(0) Shut VS up.

15
répondu nevelis 2016-07-31 05:08:07

en utilisant des versions plus récentes du compilateur MS, vous pouvez utiliser la suppression d'avertissement:

#define MY_MACRO(stuff) \
    do { \
        stuff \
    __pragma(warning(suppress:4127)) \
    } while(0)

, Vous pouvez aussi pousser/désactiver/pop, mais supprimer est beaucoup plus pratique mécanisme.

4
répondu Seth Moore 2014-09-11 19:00:17

Voici une autre approche possible, qui évite le C4127, C4548 et C6319 (avertissement d'analyse de code VS2013), et ne nécessite pas de macros ou de pragmas:

static const struct {
    inline operator bool() const { return false; }
} false_value;

do {
    // ...
} while (false_value);

cela optimise loin, et compile sans avertissements dans GCC 4.9.2 et VS2013. En pratique, il pourrait aller dans un espace de noms.

3
répondu james 2016-07-22 08:32:22

l'avertissement est dû au while(false) . Cette site donne un exemple de la façon de contourner ce problème. Exemple du site (vous devrez le retravailler pour votre code):

#define MULTI_LINE_MACRO_BEGIN do {  
#define MULTI_LINE_MACRO_END \  
    __pragma(warning(push)) \  
    __pragma(warning(disable:4127)) \  
    } while(0) \  
    __pragma(warning(pop))

#define MULTI_LINE_MACRO \  
        MULTI_LINE_MACRO_BEGIN \  
            std::printf("Hello "); \  
            std::printf("world!\n"); \  
        MULTI_LINE_MACRO_END  

il suffit d'insérer votre code entre le début et la fin.

2
répondu 2012-08-20 18:54:16

ce bug du compilateur a été corrigé dans la mise à jour 1 de Visual Studio 2015, même si le publie des notes ne le mentionne pas.

le bug a été expliqué dans l'une des réponses précédentes cependant:

résumé: cet avertissement (T4127) dans ce cas particulier est un bogue de compilateur subtil. Hésitez pas à le désactiver.

il a été conçu pour attraper des situations où l'expression logique évalue à une constante dans situations non évidentes (comme, si(a = = a && a!=a), et d'une manière ou d'une autre, il s'est transformé alors que(true) et d'Autres constructions utiles en invalide.

2
répondu chris.briend 2016-04-16 00:21:29

vous pouvez utiliser

do {
    // Anything you like
} WHILE_FALSE;

et définir plus tôt WHILE_FALSE macro comme suit:

#define WHILE_FALSE \
    __pragma(warning(push))         \
    __pragma(warning(disable:4127)) \
    while(false)                    \
  __pragma(warning(pop))

vérifié sur MSVC++2013.

2
répondu Serge Rogatch 2016-08-24 08:03:54

Ce "while(0)" s'étoffe d'un hack et vient de tourner autour de vous mordre.

votre compilateur offre-t-il #pragma s pour désactiver sélectivement et localement les messages d'erreur spécifiques? Si tel est le cas, il pourrait s'agir d'une solution raisonnable.

1
répondu Carl Smotricz 2009-12-22 13:45:48

#define STUFF for (bool b = true; b;) do {f(); g(); b = false;} while (b) ?

#define STUFF for (;;) {f(); g(); break;} ?

1
répondu ephemient 2009-12-22 18:18:55

vous pouvez utiliser comma operator au lieu de do-while(0) construct pour la macro multi-statements à utiliser dans les expressions. Donc au lieu de:

#define FOO(...)    do { Statement1; Statement2; Statement3; } while(0)

utiliser:

#define FOO(...)    (Statement1, Statement2, Statement3)

cela fonctionne indépendamment de la plate-forme et permet d'éviter l'avertissement du compilateur (même si le niveau d'avertissement le plus élevé est sélectionné). Notez que dans la virgule contenant macro (second FOO) le résultat de la dernière instruction (Statement3) serait le résultat de macro entière.

1
répondu Armen Anoyan 2013-10-07 16:21:16

je dois dire que je ne me suis jamais embêté avec le do..tandis que construire dans les macros. Tout le code dans Mes macros est lui-même inclus dans les accolades, mais sans le do -..alors. Par exemple:

#define F(x) \
    {           \
        x++;    \
    }           \

int main() {
    int a = 1;
    F(a);
    printf( "%d\n", a );
}

en outre, ma propre norme de codage (et la pratique informelle depuis des années) a été de faire tous les blocs, où qu'ils se produisent être enfermés dans des entretoises, qui élimine également plus ou moins le problème.

0
répondu 2009-12-22 13:50:32

il y a une solution mais elle ajoutera plus de cycles à votre code. N'utilisez pas de valeur explicite dans la condition while.

vous pouvez le faire comme ceci:

fichier1.h

extern const int I_am_a_zero;
#define MY_MACRO(foo,bar) \
do \
{ \
} \
while(I_am_a_zero);

la variable I_am_a_zero doit être définie dans certains .c fichier.

de toute façon cet avertissement n'apparaît pas dans GCC:)

voir cette question connexe .

0
répondu Yousf 2017-05-23 12:02:14

Vous pouvez utiliser #pragma warning:

  1. enregistrer l'état
  2. désactiver l'avertissement
  3. écrire le code fautif
  4. retourner l'avertissement à leur état antérieur

(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)

#pragma warning( push )
#pragma warning( disable: 4127 )
// Your code
#pragma warning( pop ) 

vous voulez pousser / pop les Avertissements plutôt que de désactiver/activer parce que vous ne voulez pas interférer avec les arguments en ligne de commande qui pourraient être choisis pour activer/désactiver les Avertissements (quelqu'un peut utiliser la ligne de commande pour désactiver l'avertissement, vous ne voulez pas le forcer à revenir... le code ci-dessus traite de la).

c'est mieux que d'éteindre l'avertissement globalement car vous pouvez le contrôler juste pour la partie que vous voulez. Aussi, vous pouvez le faire partie de la macro.

0
répondu TofuBeer 2011-02-24 05:21:37

Eh bien, pour moi, les travaux suivants sans le C4127 avertissement:

#define ALWAYS_TRUE(zzsome) ((##zzsome)==(##zzsome))

void foo()
{
    int a = 0;
    while( ALWAYS_TRUE(a) )
    {
    }
}

bien sûr, les compilateurs sont intelligents et zzsome ne devrait pas être une constante

0
répondu Deyan Ivanov 2015-08-13 18:20:50

cela désactivera l'avertissement et le compilateur pourra encore optimiser le code:

static inline bool to_bool(const bool v) { return v; }

if (to_bool(0)) { // no warning here
    dead_code(); // will be compiled out (by most compilers)
}

do { something(); } while(to_bool(0)); // no extra code generated
0
répondu wonder.mice 2015-12-19 22:16:55

j'ai trouvé que c'était la version la plus courte

do {
  // ... 
}
while (([]() { return 0; })())  /* workaround for MSVC warning C4172 : conditional expression is constant */

N'a pas vérifié s'il est optimisé par le compilateur, mais je suppose que c'est le cas.

0
répondu Niklas R 2016-02-09 10:09:08

vous pouvez utiliser for boucle comme:

for (;;) {
  // code
  break;
}

Macro:

#define BEGIN \
  for (;;) {

#define END \
  break; }
0
répondu wolfram77 2016-10-04 11:15:47

je préfère utiliser

for(int i = 0; i < 1; ++i) //do once
{

}

c'est l'équivalent de

do
{
}while(0);

et ne donne aucun avertissement.

-1
répondu Armen Tsirunyan 2012-10-22 12:16:53