55 votes

Alternatives à `while (1)` pour simplifier la création de branches

De temps en temps, j'utilise un while(1) bloc pour aplatir une succession d' if..else aller hors de proportion. Il va le long de ces lignes.

Au lieu de faire:

// process 
if (success) {
  // process 
  if (success) {
    //process
    if (success) {
      // etc
    }
  }
}

Je fais:

while (1) {
  // process
  if (!success) break;
  // process
  if (!success) break;
  // process
  if (!success) break;
  // etc
  break;
}

Je suis un peu agacé par l'implicite aller à la fin de l' while. Pourrais-je sortir avec un maigre construire (c'est à dire pas break à la fin)?

J'ai pu le commerce de la finale, break avec une variable (ou de registre?). Ce n'est pas exactement la plus maigre ou plus claire.

int once = 1;
while (once--) {
  // process
  if (!success) break;
  // process
  if (!success) break;
  // process
  if (!success) break;
  // etc
}

Une boucle serait un peu mieux (C99):

for (int once = 1 ; once--; once) {
  // process
  if (!success) break;
  // process
  if (!success) break;
  // process
  if (!success) break;
  // etc
}

J'ai pensé à l'aide d'un interrupteur cas. Il ne ressemble pas beaucoup mieux , mais il pourrait fonctionner.

switch (1) { default:
  // process
  if (!success) break;
  // process
  if (!success) break;
  // process
  if (!success) break;
  // etc
}

Dans ce cas particulier, le concept d'une étiquette semble imbattable.

// process
if (!success) goto end;
// process
if (!success) goto end;
// process
if (!success) goto end;
// etc

end:

Quelle autre approche les gars, vous ne connaissez/utilisez?

146voto

ouah Points 75311

Quelle autre approche les gars, vous ne connaissez/utilisez?

Vous pouvez encapsuler votre while boucle dans une fonction (et d'appeler cette fonction lorsque vous avez eu votre while boucle):

static void process(void)
{
   // process
   if (!success) return;
   // process
   if (!success) return;
   // process
   if (!success) return;
   // process
}

Tout à mi-chemin décent compilateur (par exemple, même gcc avec les optimisations désactivé) inline un static fonction si elle est appelée une fois. (Bien sûr, certaines variables peuvent avoir à être dans la portée lexicale d' process de la fonction, dans ce cas il suffit de les fournir en tant que paramètres de la fonction).

Notez que l'écriture de code de haut en bas au lieu de l'horizontale (par exemple, votre exemple avec imbriqué if) est appelé duffing. Il y a un bel article sur le sujet ici:

"La lecture du Code à Partir du Haut vers le Bas"

Aussi, dans le noyau Linux style de codage il y a un avertissement spécifique writinh contre horizontale code:

"si vous avez besoin de plus de 3 niveaux d'indentation, vous êtes foutu de toute façon, et devrait résoudre votre programme"

54voto

Fiddling Bits Points 5490

Ce qui suit est une méthode très similaire à ce que vous faites avec les boucles, mais sans la nécessité d’un compteur ou d’une déclaration break à la fin.

 do
{
    // process
    if (!success) break;
    // process
    if (!success) break;
    // process
    if (!success) break;
    ...
    // No need for a break statement here
}
while(0);
 

38voto

Clifford Points 29933

Si vous faire en sorte que le corps de chaque bloc conditionnel générer success est une fonction, comme suit ou de chaque // process peut être réduit à une expression booléenne, tels que:

success = f1() ; 
if( success ) 
{
  success = f2() ; 
  if( success ) 
  {
    success = f3() ; 
    if( success ) 
    {
      success = f4()
    }
  }
}

Ensuite, vous pouvez réduire ce phénomène à une seule expression booléenne l'exploitation de court-circuit d'évaluation:

success = f1() && 
          f2() && 
          f3() && 
          f4() ;

Ici, f2() ne sera pas appelé si f1() renvoie la valeur false et de même pour chaque appel successif - l'évaluation de l'expression abandonne sur le premier && opérande sous-expression de fausse déclaration.

25voto

Paul Roub Points 11185

Pas clair pourquoi vous auriez besoin de nidifier ou de casser. Je le fais tout le temps quand une séquence doit être remise en cause au premier échec:

 // process

if (success) {
  // more process
}

if (success) {
  // still more process
}

if (success) {
  // even more process
}
 

3voto

Dogbert Points 5138

Fiddling bits a fourni une approche commune. Une autre approche courante consiste à utiliser une seule variable / indicateur de statut pour obtenir un résultat similaire.

 bool bErr = false;

if (!bErr && success) {
   // do something
} else {
   bErr = true;
}
if (!bErr && success2) {
   // do something
} else {
   bErr = true;
}

if (bErr) {
   // hanlde cleanup from errors
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X