J'ai été ingénierie inverse du code et je suis tombé sur ce ...
/* Read in an 4 */ ret_val = read(fd, &input_integer, sizeof(int32)); CHECK_FREAD(ret_val, "reading an 4"); CHECK_FEOF(ret_val, "reading an 4"); if (input_integer != 4) { return(DCD_BADFORMAT); } /* Read in the number of atoms */ ret_val = read(fd, &input_integer, sizeof(int32)); *N = input_integer; CHECK_FREAD(ret_val, "reading number of atoms"); CHECK_FEOF(ret_val, "reading number of atoms");
8 Réponses :
Parce que ce n'est pas la même chose. Si vous mettez la même chose dans une fonction, vous aurez une fonction courte qui renvoie serait développé à: p> si, cependant, il s'agissait d'une fonction, la fonction extérieure ( une macro qui ressemble tellement à une fonction, mais se comporte différemment de manière cruciale, est une majeure no-no OMI. Je dirais oui, c'est est em> abus macro. P> p> dcd_badwrite code> si
x code> est égal -1. La macro en question revient toutefois de la fonction contenant em>. Exemple:
foobar < / Code>) Ignorerait volontiers le résultat et retournerait 0. P>
Quelle est l'alternative s'ils lisent une tonne de valeurs et veulent éliminer le code répétitif? Y a-t-il un bon moyen de faire ce qu'ils font (voir mon poste édité pour un exemple de cas)? À propos de la seule chose que je puisse penser à Porthand, il devrait avoir divisé le processus de lecture en différentes parties, comme c'est très long, car le fichier a des sections différentes ...
En C ++, exceptions. Placez le code dans une petite fonction qui, au lieu d'abuser des valeurs de retour pour signaler une défaillance, se lancent sur une erreur. Ensuite, dans l'utilisation du code, mettez la chose entière dans un essayer code> /
attrape code> et renvoyer dcd_badwrite à partir du
attrape code>. Si c'est uni clair c, alors
SETJMP code> - la manipulation des erreurs de style est probablement une meilleure solution. Et puis, peut-être que le programme hypothétique serait préférable d'utiliser une boucle en premier lieu.
@Jason: Je ne pense tout simplement pas que c'est légitime de vouloir éliminer le code répétitif ici. Surtout une fois que vous avez expliqué le fait que tous les messages sont complètement redondants, leur code "post-élimination" n'est même pas plus court que si (retval! = -1) retourner dcd_badread code>. Ce n'est certainement pas plus facile d'écrire ou de comprendre.
Dire ne pas utiliser une macro dans le cas seulement i> que sa peine d'utiliser (où vous avez besoin de substitution textuelle, pas une fonction) est un peu ridicule.
Ceci ne peut pas être fait en tant que fonction car le C'est le genre de chose qui donne à la macros un mauvais nom, car il cache une logique de contrôle vitale. P> retour code> est de retour à partir de la fonction d'appel, pas du bloc dans la macro. p>
En C ++, il faut utiliser "lancer" pour ce type de chose. En C, une macro sensiblement nommée est souvent la meilleure alternative. Voir ma réponse complète pour plus d'informations.
Eh bien, si vous définissez une fonction courte, vous devez taper plus de caractères sur chaque site d'appel. I.e.
if (check_fread(X, msg)) return DCD_BADREAD;
Dans les limites de l'espace, il a été mis en œuvre, il a peut-être été bien (bien qu'il soit généralement fronçonné en C ++).
La chose la plus criante à ce sujet qui m'inquiète, c'est que certains développeurs nouvellement introduits pourraient voir cela et penser à faire p> qui est évidemment faux. p> < P> En outre, il semble que msg code> n'est utilisé que si vous consommez / attendu dans
DCD_BADREDAD code> qui aggrave la situation ... P> P>
Les développeurs nouvellement introduits feront des erreurs stupides, comme utiliser la valeur de retour d'une fonction (ou le résultat d'une expression) sans vous soucier de rechercher ce que c'est réellement. Pas beaucoup de point en essayant de rendre compte de cela.
@Steve: D'autre part, les présentant des macros particulièrement confuses semble méchant et contre-productif. En particulier lorsque la macro est mal formée et la documentation trompeuse.
Vrai, mais que ce soit une bonne macro ou une mauvaise macro ou une mauvaise (et j'accepte que c'est un mauvais), il convient de dire que la même chose de toute macro i> qui ne se développe pas pour donner une expression: "Si Quelqu'un écrit si (macro (...)) {...} else {...} code>, alors cela ira mal ".
Que ce soit ou non, une abus est une question de goût. Mais je vois des problèmes principaux avec celui-ci p>
si code> et un possible
Dangling sinon code> problème li>
- la nommée ne suggère pas que c'est
est un retour préliminaire de la
Fonction environnante li>
ol>
donc c'est définitivement très mauvais style. p>
Si la macro est dans un fichier source et utilisée uniquement dans ce fichier, je le trouve un peu moins offensant que si elle est désactivée dans une en-tête quelque part. Mais je n'aime pas beaucoup une macro qui revient, (surtout une documentée em> pour mettre fin à l'application et revenir en réalité), et toujours moins celle qui revient conditionnellement, car elle le rend assez facile à créer La fuite de mémoire suivante: Si je crois que la documentation, je n'ai aucun motif de suspecter que ce code fuit la mémoire chaque fois que la lecture échoue. Même si la documentation était correcte, je préfère que le flux de contrôle dans C soit éventuellement évident, ce qui signifie pas caché par les macros. Je préférerais également que mon code soit vaguement cohérent entre les cas où j'ai des ressources pour nettoyer et étudier où je ne le fais pas, plutôt que d'utiliser la macro pour un mais pas l'autre. Donc, la macro n'est pas à mon goût même si ce n'est pas définitivement abusif. P> faire ce que dit la documentation, je préférerais écrire quelque chose comme: p> avec faire ce que la macro fait réellement, je voudrais Préfère ignorer la macro entièrement et écrire: p> vérifier code> être une fonction. Ou utilisez un
affirmer code>. Bien sûr, une affirmation ne fait que quelque chose si NDEBUG n'est pas défini, il n'est donc pas bon de la manipulation des erreurs si vous planifiez des constructions distinctes de débogage et de libération. P>
if (retval == -1) return DCD_BADREAD;
Très probablement, lors du débogage, il est utile d'activer le code qui enregistre la valeur en msg et renvoie. Pendant la production, le code de journalisation est inutile. Quitter la macro en place permet de refaire la journalisation si elle est nécessaire.
@supercat: La documentation décrit donc le comportement de débogage pour lequel aucun code n'existe dans le fichier, mais que le programmateur de débogage doit être mis en œuvre et insérer si nécessaire? Au lieu du comportement de production pour lequel le code existe? Ensuite, oui, c'est sans aucun doute un abus colossal ;-)
Très probablement, le code de journalisation existait à un moment donné dans le passé, mais a été supprimé. Ma préférence aurait été d'utiliser une macro imbriquée pour la pièce de journalisation et d'utiliser un drapeau logging_enable pour définir une macro imbriquée pour connecter quelque chose ou ne rien faire.
Je suis sur la clôture de savoir s'il faut appeler une telle macro * abus *, mais je dirai que ce n'est pas une bonne idée.
Je dirais que en général, vous devriez éviter d'utiliser plus, cette macro peut causer des problèmes avec le flux de code en fonction de la manière dont il est utilisé. Par exemple, le code p> ne ferait pas ce que vous penseriez que ce serait (le En outre, le deuxième argument n'est pas utilisé. Le problème évident ici est la mise en œuvre ne correspondant pas à la documentation. Le problème caché est lorsque la macro est invoquée comme ceci: p> Vous vous attendez à ce que le pointeur passe à l'élément de tableau suivant après l'appel de la macro. Cependant, le deuxième paramètre n'est pas utilisé, l'incrément n'arrive jamais. C'est une autre raison pour laquelle les déclarations avec des effets secondaires causent des problèmes dans les macros. P> au lieu d'utiliser une macro pour faire tout cela, pourquoi ne pas écrire une fonction pour encapsuler le aussi longtemps que tout votre Appels vers J'avoue que beaucoup de gens ont peur de retour code> dans une macro. Il est difficile de créer une macro qui gère le retour correctement sans effectuer le flux de contrôle de la fonction qui l'appelle maladroit ou difficile à comprendre. Vous ne voulez certainement pas "accidentellement" de retourner d'une fonction sans le réaliser. Celui-ci peut être ennuyeux de déboguer. P>
sinon code> devient associé au
si code> à l'intérieur de la macro). La macro doit être clôturée dans
{} code> pour vous assurer qu'il ne modifie pas de conditionnels environnants. P>
lire code> et L'erreur vérifie? Il peut retourner zéro sur le succès ou un code d'erreur. Si le code de traitement des erreurs est commun entre tous les blocs code> lisez code>, vous pouvez faire quelque chose comme ceci: p>
Read_Helper Code> Attribuer leur valeur de retour à
RET CODE>, vous pouvez réutiliser le même bloc de code de traitement des erreurs dans toute la fonction. Votre fonction
print_error_message_for_code code> prendrait simplement un code d'erreur comme entrée et utilisez un commutateur code> ou un tableau pour imprimer un message d'erreur qui correspond à celui-ci. P>
goto code>, mais réutilisant le code de traitement des erreurs courantes au lieu d'une série de blocs imbriqués et de variables de condition peuvent être un cas d'utilisation approprié pour celui-ci. Il suffit de le garder propre et lisible (une étiquette par fonction, et conservez le code de manipulation d'erreur simple). P> P>
Je considérerais l'exemple d'abus de macro pour deux raisons: (1) Le nom de la macro ne précise pas ce qu'il fait, notamment qu'il pourrait revenir; (2) La macro n'est pas syntaxiquement équivalente à une déclaration. Le code comme échouera. Mon changement préféré: p>
Cette macro n'imprime pas un message d'erreur car il devrait en fonction de sa description dans les commentaires. Est-ce un code complet?
Oui, c'est le code complet. Et à Chrisf, voir l'exemple que j'ai ajouté.
Et pourquoi l'argument "MSG" n'est-il pas utilisé? Les commentaires ne correspondent pas à la mise en œuvre, ce qui signifie qu'au moins un est buggy, mais probablement tous les deux. Il serait préférable d'écrire un
tad_t coché_fread_fread (refuge de mémoire tampon, Taille_t éléments, Taille_t numitems, fichier * FP, Const Char * msg) CODE> Fonction et utilisation de manière systématique. Il est également intéressant de spéculer pourquoi il vérifie -1;
Fread () Code> retourne 0 ou un nombre court sur l'erreur - et le type de retour est
Taille_t code> qui exclut une valeur de retour de -1 pour presque tous les objectifs.
Mais est-ce considéré comme abusé de qc? C'est myy question. @Jonathan Je ne sais pas pourquoi ils n'utilisent pas msg ... oubli? paresseux? confusion? vous choisissez! Mais tu as absolument raison, c'est étrange ....
Ils ont probablement utilisé l'attribut MSG lors du test du code et ils ont emporté le code d'impression avant de la libérer. J'ai d'abord pensé à cela comme un moyen d'insérer des commentaires dans le code, mais pourquoi ne pas utiliser honnête / * commentaires * / à la place?
Abus vs mauvaise utilisation? Difficile de dire ... puisque MSG est inutilisé, il est quelque peu inutile. Clairement, les commentaires sur
Fread () code> ne sont pas germes to
lire () code>. Puisque nous ne pouvons pas voir check_feof (), nous ne pouvons pas dire ce que cela fait. Cependant, il me semble que une fonction simple de gérer les deux conditions serait meilleure: elle pourrait envelopper la fonction
lue () code> (appel système) et séparer le statut d'erreur de tout le reste:
si ((retval = enveloppé enroulée (FD, et INPUT_Integer, Tailleof (int32), "Lecture d'un 4")! = DCD_NOERROR) Retournez Reval; code>. Et si le test de 4 est omniprésent, je l'envelopperais encore plus loin. Je pense que c'est la maltraitance macro.