Alternatives à `while (1)` pour simplifier le twigment

De temps en temps, j’utilise un bloc while(1) pour aplatir une succession de if..else hors de proportion. Cela va dans ce sens.

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 contrarié par le saut implicite à la fin du while . Pourrais-je m’en sortir avec une construction plus mince (c.-à-d. Pas de break à la fin)?

Je pourrais échanger la break finale avec une variable (ou m’inscrire?). Ce n’est pas exactement plus mince ou plus clair.

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

Une boucle for 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é à utiliser un boîtier de commutation. Cela ne semble pas beaucoup mieux, même si cela fonctionnerait.

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

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

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

Quelle autre approche connaissez-vous / utilisez-vous?

Ce qui suit est une méthode très similaire à ce que vous faites avec les boucles, mais sans avoir besoin d’un compteur ou d’une instruction de 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); 

Quelle autre approche connaissez-vous / utilisez-vous?

Vous pouvez encapsuler votre boucle while dans une fonction (et appeler cette fonction là où vous aviez votre boucle while):

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

Tout compilateur à moitié correct (par exemple, même gcc avec des optimisations désactivées) incorporera une fonction static si elle est appelée une fois. (Bien sûr, certaines variables doivent être dans la scope lexicale de la fonction de process , dans ce cas, il suffit de les fournir en tant que parameters de la fonction).

Notez que l’écriture de code de haut en bas au lieu d’horizontal (par exemple, votre exemple avec nested if ) s’appelle duffing . Il y a un bel article sur le sujet ici:

“Code de lecture de haut en bas”

En outre, dans le style de codage du kernel Linux, il existe un avertissement spécifique contre le code horizontal:

“Si vous avez besoin de plus de 3 niveaux d’indentation, vous êtes de toute façon foutu et vous devriez corriger votre programme”

Si vous faites en sorte que le corps de chaque bloc conditionnel générant le success soit une fonction comme suit ou que chaque // process puisse être réduit à une expression booléenne, par exemple:

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

Vous pouvez ensuite réduire cette valeur à une seule expression booléenne exploitant l’évaluation des courts-circuits:

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

Ici, f2() ne sera pas appelé si f1() retourne faux et le même pour chaque appel successif. L’évaluation de l’expression s’interrompt sur la première sous-expression opérante && pour renvoyer false.

Pas clair pourquoi vous auriez besoin de nicher ou de casser. Je le fais tout le temps quand une séquence doit être libérée au premier échec:

 // process if (success) { // more process } if (success) { // still more process } if (success) { // even more process } 

Fiddling bits a fourni une approche commune. Une autre approche courante consiste à utiliser une variable / un indicateur de statut unique 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 } 

Une autre option consisterait à utiliser une variable de drapeau simple

 bool okay = true; if(okay &= success){ // process } if(okay &= success){ // process } if(okay &= success){ // process }