Supposons que je veuille écrire une fonction qui concatène deux chaînes en C. La façon dont je l'écrirais est la suivante:
void concat(char s[], char t[]){
int i = 0;
int j = 0;
while (s[i] != '\0'){
i++;
}
while (t[j] != '\0'){
s[i] = t[j];
i++;
j++;
}
s[i] = '\0';
}
Cependant, K&R dans leur livre l'a implémenté différemment, notamment en incluant autant que possible la partie condition de la boucle while:
void concat(char s[], char t[]){
int i, j;
i = j = 0;
while (s[i] != '\0') i++;
while ((s[i++]=t[j++]) != '\0');
}
Quelle voie est préférée? Est-il encouragé ou découragé d'écrire du code comme le font K&R? Je crois que ma version serait plus facile à lire par d'autres personnes.
Préférez toujours la clarté à l'intelligence. Auparavant, le meilleur programmeur était celui dont personne ne pouvait comprendre le code. "Je ne peux pas comprendre son code, il doit être un génie", ont-ils dit. De nos jours, le meilleur programmeur est celui dont tout le monde peut comprendre le code. Le temps de l'ordinateur est désormais moins cher que celui du programmeur.
Tout imbécile peut écrire du code qu'un ordinateur peut comprendre. Les bons programmeurs écrivent du code que les humains peuvent comprendre. (M. Fowler)
Donc, sans aucun doute, je choisirais l'option A. Et c'est ma réponse définitive.
La règle d'or, comme dans la réponse de Tulains Córdova, est de s'assurer d'écrire du code intelligible. Mais je ne suis pas d'accord avec la conclusion. Cette règle d'or signifie écrire du code que le programmeur typique qui finira par maintenir votre code peut comprendre. Et vous êtes le meilleur juge pour savoir qui est le programmeur type qui finira par maintenir votre code.
Pour les programmeurs qui n'ont pas commencé par C, la première version est probablement plus facile à comprendre, pour des raisons que vous connaissez déjà.
Pour ceux qui ont grandi avec ce style de C, la deuxième version pourrait bien être plus facile à comprendre: pour eux, il est tout aussi compréhensible de ce que fait le code, pour eux, cela laisse moins de questions pourquoi il est écrit tel quel, et pour eux , moins d'espace vertical signifie que plus de contexte peut être affiché à l'écran.
Vous devrez vous fier à votre bon sens. À quel public souhaitez-vous rendre votre code plus facile à comprendre? Ce code est-il écrit pour une entreprise? Ensuite, le public cible est probablement les autres programmeurs de cette entreprise. Est-ce un projet de passe-temps personnel sur lequel personne ne travaillera que vous-même? Ensuite, vous êtes votre propre public cible. Est-ce ce code que vous souhaitez partager avec d'autres? Ensuite, ces autres sont votre public cible. Choisissez la version qui correspond à ce public. Malheureusement, il n'y a pas de moyen unique d'encourager.
EDIT: La ligne s[i] = '\0';
a été ajouté à la première version, ce qui le corrige comme décrit dans la variante 1 ci-dessous, donc cela ne s'applique plus à la version actuelle du code de la question.
La deuxième version a l'avantage distinctif d'être correct, tandis que la première ne l'est pas - elle ne termine pas correctement la chaîne cible.
La "cession en condition" permet d'exprimer le concept de "copier chaque caractère avant de vérifier le caractère nul" de manière très concise et d'une manière qui rend l'optimisation pour le compilateur est un peu plus facile, bien que de nombreux ingénieurs logiciels trouvent de nos jours ce style de code moins lisible. Si vous insistez pour utiliser la première version, vous devrez soit
Les réponses de Tulains Córdova et hvd couvrent assez bien les aspects de clarté/lisibilité. Permettez-moi d'ajouter la portée comme une autre raison en faveur des affectations dans des conditions. Une variable déclarée dans la condition n'est disponible que dans la portée de cette instruction. Vous ne pouvez pas utiliser cette variable par la suite par accident. La boucle for fait cela depuis des siècles. Et il est suffisamment important que le prochain C++ 17 introduit une syntaxe similaire pour if et switch :
if (int foo = bar(); foo > 42) {
do_stuff();
}
foo = 23; // compiler error: foo is not in scope
Non. C'est un style C très standard et normal. Votre exemple est mauvais, car il ne devrait s'agir que d'une boucle for, mais en général il n'y a rien de mal à
if ((a = f()) != NULL)
...
par exemple (ou avec while).
Les deux styles sont bien formés, corrects et appropriés. Laquelle est la plus appropriée dépend en grande partie des directives de style de votre entreprise. Les IDE modernes faciliteront l'utilisation des deux styles grâce à l'utilisation de la syntaxe en direct qui met explicitement en évidence les zones qui pourraient autrement devenir une source de confusion.
Par exemple, l'expression suivante est mise en évidence par Netbeans :
if($a = someFunction())
pour "affectation accidentelle".
Pour dire explicitement à Netbeans que "oui, je voulais vraiment faire ça ...", l'expression peut être enveloppée dans un ensemble de parenthèses.
if(($a = someFunction()))
En fin de compte, tout se résume aux directives de style d'entreprise et à la disponibilité d'outils modernes pour faciliter le processus de développement.
Au temps de K&R
while ((s[i++]=t[j++]) != '\0')
correspondrait à une instruction sur la plupart des processeurs (je m'attends à la Dec VAC) Il y a des jours
(Une note sur toujours utiliser des accolades - le 1er ensemble de code prend plus de place en raison d'avoir un "inutile" {}
, d'après mon expérience, ceux-ci empêchent souvent le code qui a été mal fusionné du compilateur et permettent des erreurs avec des ";" incorrects emplacements à détecter par les outils.)
Cependant, autrefois, la 2e version du code aurait été lue. (Si j'ai bien compris!)
concat(char* s, char *t){
while (*s++);
--s;
while (*s++=*t++);
}
Même pouvoir le faire est une très mauvaise idée. Il est familièrement connu comme "Le dernier bug du monde", comme ceci:
if (alert = CODE_RED)
{
launch_nukes();
}
Bien que vous ne risquiez pas de faire une erreur tout à fait aussi grave, il est très facile de visser accidentellement et de provoquer une erreur difficile à trouver dans votre base de code. La plupart des compilateurs modernes insèrent un avertissement pour les affectations dans un conditionnel. Ils sont là pour une raison, et vous feriez bien de les écouter et d'éviter simplement cette construction.