Mais qu'en est-il des commandes continue et break? peut-on leur donner une étiquette pour sortir de plus d'un niveau d'imbrication?
Salut,
Non, à part goto, il n'y a pas de break qui disent de sortir de plusieurs niveaux d'imbrication.
Mais l'idée est d'éviter de faire trop de niveaux d'imbrication Et pour ça, on peut par exemple faire des fonctions. Si tu as un double for, et que dedans tu veux encore faire des for, et bien tu appelles une fonction. Et ainsi avec un return bien placé, tu pourras sortir de tous les for de la fonction ou tu es, qui dépend de la sémantique.
Mais l'idée est d'éviter de faire trop de niveaux d'imbrication
Vu l'orientation du langage C au début, l'idée de Ritchie, c'est certainement que si tu veux sortir de plusieurs niveaux d'un coup, tu mets un goto, et où est le problème ?
for(int i = .....) {
for(int j = ......) {
for(int k = .....) {
....
if (some_reason) goto exit_of_ijk_loops;
...
}
}
}
exit_of_ijk_loops:
Avec des noms bien choisis, c'est parfaitement clair, bien plus qu'un bidouillage à coup d'indicateurs (qui ont leur intérêt dans d'autres occasions).
Forcément, si tu appelles les étiquettes l1, l2, l3, ça va pas faire le même effet en terme de lisibilité.
Pour des continue, quelque chose du genre
for (int i = ....) {
for (int j = ......) {
for (int k = .....) {
...
if (...) goto continue_with_next_i;
}
}
continue_with_next_i:
}
Il ne faut pas confondre le code spaghetti, avec des gotos qui vont n'importe où sans logique apparente, et des tournures idiomatiques, comme l'utilisation du goto pour la libération des ressources en cas d'échec
bool traitement() {
bool ok = false;
Ressource *a = reservation(....);
if (a == NULL) goto echec_reservation_a;
faire_quelque_chose();
Ressource *b = reservation(....);
if (b == NULL) goto echec_reservation_b;
faire autre_chose();
Ressource *c = reservation(....);
if (c == NULL) goto echec_reservation_c;
// normalement
faire le_boulot_normal();
ok = true;
// quand ça se passe mal on arrive directement ci-dessous
echec_reservation_c:
liberer(b);
echec_reservation_b:
liberer(a);
echec_reservation_a:
return erreur;
}
(un truc qu'on retrouve un peu partout dans les modules du noyau linux)
L'idée de mon post était de "continuer" à l'élément suivant de la boucle externe si on a un échec dans la boucle interne. Je saute ce qui suit la boucle interne avant la fin de la boucle externe.
Je suis d'accord que mon étiquette n'était pas explicite, mais c'était un exemple.
Le Tout est souvent plus grand que la somme de ses parties.
Il y a une différence entre les humains et les compilateurs. Ils peuvent générer du code spaguetti sans se tromper et rendre des comptes. Il y a tout de même moyen de coder en assembler de façon propre.
Le Tout est souvent plus grand que la somme de ses parties.
En fait, le C est un langage procédural : la philosophie, c'est l'appel des fonctions, pas le goto. Voila pourquoi le goto est mal vu.
Le goto est "mal vu" pour des raisons dogmatiques. Il n'y a pas plus de raison de mal le voir qu'aucun autre mécanisme du langage. Ça existe, et si on s'en sert à bon escient, tout va bien.
On va pas refaire l'histoire des idées en programmation, mais il faut se rappeler que dans les années 60, la norme était de programmer les boucles et les tests avec des branchements, parce que c'était quasiment la seule façon de faire dans les langages sérieux comme cool et fortran (qui n'avait que la boucle do avec compteur).
Dijkstra, Wirth et toute la bande des algolistes ont lutté pour faire passer l'idée d'une programmation structurée, utilisant des structures de contrôles (boucles, alternatives...) pour que la forme du code en reflète clairement la logique. La question etait de savoir quelles structures implanter dans les langages, parce que si en théorie (le théorème de boëhm et jacopini !) Il suffit d'avoir si le et ifthenelse pour se passer du goto, en pratique ça ne donne pas du code clair,au contraire.
Donc il y a un compromis , quand on concoit un langage de programmation, à décider quelles structures de contrôle on integre dans le langage. Pour c, a philosophie c'était service minimum : if' switch for do et dowhile, et pour le reste débrouillez vous avec break, continue et goto. C'est tout. Meme pas de fonctions emboîtees
Maintenant l'aspect dogmatique, ca a ete quand il a fallu lutter violemmment pour convaincre ceux qui connaissaient basic, ou fortran d'arreter de tout faire avec ces putains de goto quand c'est plus simple de mettre un while ou un if then else. Le côté ayatollah, c'est de l'interdire totalement au prétexte que des sagouins peuvent l'utiliser de travers.
Enfin, si vous voulez avoir une idée de la vraie philosophie de c, regardez le code pondu par ceux qui l'ont inventé. Les sources des premières versions d'Unix, par exemple. Et comptez les goto. Prévoyez un sac en papier à portée de main.
flag() {
extern getc, peekc;
auto c, f;
f = 0;
l1:
switch(c=getc()) {
case 'w':
f = 1;
goto l1;
case 'i':
f = 2;
goto l1;
case 'b':
f = 3;
goto l1;
case 'f':
f = 4;
goto l1;
case 'd':
f = 5;
goto l1;
case 'p':
f =+ 16;
goto l1;
}
peekc = c;
return(f);
}
// C légèrement modernisé
int flag() {
char c;
int f = 0;
int looping = 1;
do {
switch (c = getc()) {
case 'w':
f = 1;
break;
case 'i':
f = 2;
break;
case 'b':
f = 3;
break;
case 'f':
f = 4;
break;
case 'd':
f = 5;
break;
case 'p':
f += 16;
break;
default:
looping = 0;
}
} while (looping);
peekc = c;
return(f);
}
Je ne te citerai pas car je fous la merde dans ce cas. Je suis pleinement d'accord avec toi. Il ne faut pas être plus catholique que le pape!
En passant, ma synthèse vocale m'a presque dit goto hell!
Ton code est suffisamment clair et je ne vois pas ce qu'on aurait à redire sur celui-ci. Si on a gardé des goto, continue et break dans C, et ce, malgré la revision de 1999, c'est peut-être parce qu'on peut s'en servir. Il faut le faire à bon escient.
Le Tout est souvent plus grand que la somme de ses parties.
Et l'histoire de faire des fonctions et des returns ne marche pas à tout les coups, les destinations des "échappements" pouvant être différentes
for (int i = ...) {
for (int j = ......) {
for (int k = ....) {
...
if (raison_x(i,j,k)) goto try_another_j;
...
if (raison_y(i,j,k)) goto give_up;
...
if (raison_xy(i,j,k) goto try_another_i;
...
}
try_another_j;
}
try_another_i:
}
give_up:
(ce qui arrive dans les programmes de recherche d'une solution par backtracking, par exemple).
* Si on a gardé tout ça dans C, c'est parce que les gens qui programment en C en ont absolument besoin
parce que le code existant doit continuer à tourner
parce que le reste du langage est insuffisant pour exprimer ce qu'on veut faire
En pratique, l'absence de "break" et "continue" à plusieurs niveaux n'est pas dramatique, au lieu d'écrire, comme en java
//Java
oop_over_array: for(int i = .....) {
....
for(....) {
if (....) break loop_over_array;
}
}
on écrira
// C
for (.....) {
....
if (...) goto end_of_loop_over_array;
}
end_of_loop_over_array:
(en java l'étiquette désigne l'instruction qui sera cassée par le break)
c'était quasiment la seule façon de faire dans les langages sérieux comme cool et fortran
Le langage Cool, un langage sérieux ?
(J'adore la faute de frappe ! )
Tiens, il y a un autre dogme dont j'ai entendu parler ici : pas de variables globales. En langage Cool, elles le sont toutes (et c'est sacrément pénible...)
Si tu parles de cobol, dont ma connaissance s'arrete au standard 85, les sous programmes peuvent être compilés séparément (et chargés dynamiquement !), on peut donc avoir des variables locales.
Aux dernières nouvelles, en C++, std::out et ses copains sont des variables globales :-)
Ceci dit, moins on en a mieux on se porte. Mais si c'est pour passer en paramètre à tout le monde une variable déclarée dans le main, c'est de la connerie.
Si vous voulez sortir les vieux langages du placard, que dire des common de Fortran?
Mêm en assembler (les vieux également) on a des espaces externes semblables au common.
Moi aussi, je n'ai rien contre les variables globbales si on peut éviter de les passer en paramètres aux fonctions, surtout si on doit le faire pour presque toutes les fonctions.
Le Tout est souvent plus grand que la somme de ses parties.
Si tu parles de cobol, dont ma connaissance s'arrete au standard 85, les sous programmes peuvent être compilés séparément (et chargés dynamiquement !), on peut donc avoir des variables locales.
Disons que les variables sont globales par rapport au fichier. Mais en effet ce n'est pas global tout court.
Quant au débat sur le dogmatisme, je pense qu'il ne faut pas confondre moyen et but. Le but, c'est d'écrire des programmes qui marchent, sont maintenables, dont le code est lisible, etc. Éviter les goto et les variables globales peut faciliter l'atteinte de ce but, mais n'est pas le but en soi.)
Tout à fait d'accord. Ca _peut_, souvent, pas toujours.
Et vouloir à tout pris éviter les goto et les variables globales peut aussi rendre la programmation moins lisible et moins maintenable. C'est une question de circonstances, et le mot d'ordre "jamais de gotos ni de variables globales parce que c'est mal" fait plus de mal que de bien, parce qu'il empêche de se poser des questions sur ce qu'on fait, en terme de libilité et de maintenabilité justement.
Les commons de Fortran ? En fait il y avait deux usages
l'usage normal qui était de partager des variables globales
l'utilisation pour économiser de la place : une zone mémoire temporaire, redéfinie à la convenance de chaque sous-programme pour y mettre ses variables temporaires, du moment que 2 sous programmes n'utilisent pas le common en meme temps.
(à l'époque, on n'utilisait pas forcément une pile pour stocker les variables locales qu'on appelle maintenant "automatiques").
Le premier usage était raisonnable, le second une source d'emmerdements, mais il fallait tasser pour faire tourner les programmes sur des dizaines de Ko, pas des Megas.
Michel, tu as raison pour les vieilles machines, les mémoires étaient en méga (et encore) et non en giga. Elles n'avaient pas toujours de piles.
As-tu déjà travaillé sur un Z80 avec 64 Ko? C'était un jouet.
Voir sur Wikipédia les séries 6000 de Control Data
Le _blank_ common facilitait l'extension de la mémoire requise.
Le Tout est souvent plus grand que la somme de ses parties.
Les étiquettes en C
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Le Tout est souvent plus grand que la somme de ses parties.
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.