Un bloc est une liste d'instructions à exécuter. Les exemples où les blocs apparaissent en C sont après une instruction while et dans les instructions if
while( boolean expression)
statement OR block
if (boolean expression)
statement OR block
C permet également à un bloc d'être imbriqué dans un bloc. Je peux l'utiliser pour réutiliser les noms de variables, supposons que j'aime vraiment 'x'
int x = 0;
while (x < 10)
{
{
int x = 5;
printf("%d",x)
}
x = x+1;
}
imprimera le nombre 5 dix fois. Je suppose que je pourrais voir des situations où garder le nombre de noms de variables bas est souhaitable. Peut-être en expansion macro. Cependant, je ne vois aucune raison sérieuse d'avoir besoin de cette fonctionnalité. Quelqu'un peut-il m'aider à comprendre les utilisations de cette fonctionnalité en fournissant des idiomes où elle est utilisée.
Réponses:
L'idée n'est pas de limiter le nombre de noms de variables ou d'encourager la réutilisation des noms, mais plutôt de limiter la portée des variables. Si tu as:
alors la portée de
y
est limitée au bloc, ce qui signifie que vous pouvez l'oublier avant ou après le bloc. Vous voyez cela utilisé le plus souvent en relation avec les boucles et les conditions. Vous le voyez également plus souvent dans les langages de type C tels que C ++, où une variable hors de portée entraîne sa destruction.la source
Parce que dans les temps anciens de C, de nouvelles variables ne pouvaient être déclarées que dans un nouveau bloc.
De cette façon, les programmeurs pourraient introduire de nouvelles variables au milieu d'une fonction sans la divulguer et en minimisant l'utilisation de la pile.
Avec les optimiseurs d'aujourd'hui, c'est inutile et c'est un signe que vous devez envisager d'extraire le bloc dans sa propre fonction.
Dans une instruction switch, il est utile de placer les cas dans leurs propres blocs pour éviter la double déclaration.
En C ++, il est très utile, par exemple, pour les gardes de verrouillage RAII et pour garantir que les destructeurs exécutent le verrou de libération lorsque l'exécution sort du cadre et continuent de faire d'autres choses en dehors de la section critique.
la source
Je ne le considérerais pas comme des blocs "arbitraires". Ce n'est pas une fonctionnalité tant destinée aux développeurs, mais la façon dont C utilise les blocs permet d'utiliser la même construction de blocs à plusieurs endroits avec la même sémantique. Un bloc (en C) est une nouvelle portée, et les variables qui le quittent sont éliminées. Ceci est uniforme quelle que soit la façon dont le bloc est utilisé.
Dans d'autres langues, ce n'est pas le cas. Cela a l'avantage de permettre moins d'abus comme vous le montrez, mais l'inconvénient que les blocs se comportent différemment selon le contexte dans lequel ils se trouvent.
J'ai rarement vu des blocs autonomes utilisés en C ou C ++ - souvent quand il y a une grande structure ou un objet qui représente une connexion ou quelque chose dont vous voulez forcer la destruction. Habituellement, cela indique que votre fonction fait trop de choses et / ou est trop longue.
la source
Vous devez comprendre que les principes de programmation qui semblent maintenant évidents ne l'ont pas toujours été. Les meilleures pratiques C dépendent en grande partie de l'âge de vos exemples. Lorsque C a été introduit pour la première fois, la division de votre code en petites fonctions était considérée comme trop inefficace. Dennis Ritchie a essentiellement menti et a déclaré que les appels de fonction étaient vraiment efficaces en C (ce n'était pas le cas à l'époque), ce qui a incité les gens à les utiliser davantage, bien que les programmeurs C n'aient jamais vraiment dépassé complètement une culture d'optimisation prématurée.
Il est une bonne pratique de programmation, aujourd'hui encore , de limiter la portée de vos variables aussi faible que possible. De nos jours, nous le faisons généralement en créant une nouvelle fonction, mais si les fonctions sont considérées comme coûteuses, l'introduction d'un nouveau bloc est un moyen logique de limiter votre portée sans la surcharge d'un appel de fonction.
Cependant, j'ai commencé à programmer en C il y a plus de 20 ans, à l'époque où vous deviez déclarer toutes vos variables en haut d'une étendue, et je ne me souviens pas que l'observation de variables comme celle-là ait jamais été considérée comme un bon style. Redéclarer en deux blocs l'un après l'autre comme dans une instruction switch, oui, mais pas d'observation. Peut - être que si la variable était déjà utilisée et que le nom spécifique était très idiomatique pour l'API que vous appelez, comme
dest
etsrc
dansstrcpy
, par exemple.la source
Les blocs arbitraires sont utiles pour introduire des variables intermédiaires qui ne sont utilisées que dans des cas particuliers de calcul.
Il s'agit d'un modèle courant dans le calcul scientifique, où les procédures numériques généralement:
En raison du deuxième point, il est utile d'introduire des variables temporaires de portée limitée, ce qui est obtenu soit en utilisant un bloc arbitraire, soit en introduisant une fonction auxiliaire.
Bien que l'introduction d'une fonction auxiliaire puisse ressembler à une évidence ou à une meilleure pratique à suivre aveuglément, il y a en fait peu d'avantages à le faire dans cette situation particulière.
Parce qu'il y a beaucoup de paramètres et de quantités intermédiaires, nous voulons introduire une structure pour les passer à la fonction auxiliaire.
Mais, comme nous voulons être conséquents avec nos pratiques, nous n'introduirons pas seulement une fonction auxiliaire mais plusieurs. Donc, si nous introduisons des structures ad-hoc véhiculant des paramètres pour chaque fonction, ce qui introduit beaucoup de surcharge de code pour déplacer les paramètres d'avant en arrière, ou nous en introduisons un qui les gouvernera toute la structure de la feuille de calcul, qui contient toutes nos variables mais ressemble à un grappin de bits sans consistance, où à tout moment seule la moitié des paramètres a une signification intéressante.
Par conséquent, ces structures auxiliaires sont généralement encombrantes et les utiliser signifie choisir entre une surcharge de code ou introduire une abstraction dont la portée est trop large et affaiblir le sens du programme, au lieu de le renforcer .
L'introduction de fonctions auxiliaires pourrait faciliter les tests unitaires du programme en introduisant une granularité de test plus fine, mais en combinant les tests unitaires pour ne pas que les procédures de bas niveau et les tests de régression sous forme de comparaisons (avec numdiff) des traces numériques des procédures font un travail tout aussi bon .
la source
En général, la réutilisation des noms de variables de cette manière provoque trop de confusion pour les futurs lecteurs de votre code. Il vaut mieux simplement nommer la variable interne autre chose. En fait, le langage C # interdit spécifiquement l'utilisation de variables de cette manière.
Je pouvais voir comment l'utilisation de blocs imbriqués dans les extensions de macro serait utile pour empêcher les collisions de noms de variables.
la source
C'est pour délimiter des choses qui n'ont normalement pas de portée à ce niveau. Ceci est extrêmement rare, et en général, le refactoring est un meilleur choix, mais je l'ai rencontré une ou deux fois dans le passé dans les instructions switch:
Lorsque vous envisagez la maintenance, la refactorisation doit être équilibrée avec toutes les implémentations d'affilée, tant que chacune ne comporte que quelques lignes. Il peut être plus facile de les avoir tous ensemble, plutôt qu'une liste de noms de fonctions.
Dans mon cas, si je me souviens bien, la plupart des cas étaient de légères variations du même code - sauf que l'un d'entre eux était identique à un autre, juste avec un prétraitement supplémentaire. Un commutateur a fini par être la forme la plus simple à prendre pour le code, et la portée supplémentaire a permis l'utilisation de variables locales supplémentaires dont lui et d'autres cas n'avaient pas à s'inquiéter (tels que les noms de variables se chevauchant accidentellement avec un défini avant le commutateur, mais utilisé plus tard).
Notez que l'instruction switch est simplement son utilisation que j'ai rencontrée. Je suis sûr que cela peut s'appliquer ailleurs aussi, mais je ne me souviens pas de les avoir utilisés efficacement de cette façon.
la source