9
votes

Façons d'éviter / diminuer la douleur de la valeur de retour Vérification après chaque appel de fonctions?

Dans les langues et / ou les bibliothèques qui ne prennent pas en charge les exceptions, de nombreuses fonctions renvoient une valeur indiquant le succès ou l'échec de leur fonctionnement - l'exemple le plus connu étant peut-être des appels système non * x tels que ouvert ( ) code> ou CHDIR () code> ou certaines fonctions libc.

Quoi qu'il en soit, lorsque j'écris C code, il finit très souvent comme ceci: p>

int retval;
...
retval = my_function(arg1, arg2);
if (retval != SUCCESS_VALUE) { do_something(); }

retval = my_other_function(arg1, arg2);
if (retval != SUCCESS_VALUE) { do_something_else(); }


9 commentaires

@sbi oui, je pense que nous sommes tous d'accord pour dire que c a des "problèmes" :)


Pendant ce temps, personne ne m'a rejoint dans mon vote judicieux pour la fermer comme étant principalement basé sur l'opinion (qui a précédé la guerre des langues).


Dans une langue sans manipulation d'exception, c'est à peu près ce que vous devrez faire pour ne pas manquer une erreur.


@Jimbalter je l'ai maintenant fait.


assert n'est pas pour la manipulation des erreurs


@JIM: Je n'ai pas parce que c'est pas basé sur l'opinion. (Si vous pensez que "écrire ce code suce" est une opinion, vous devez être éduqué. :) )


@SBI approche de ce problème est variée et individuelle ... c'est très une question d'opinion comment le résoudre.


@JIM: S'il vous plaît dites-moi une zone dans la programmation où les approches ne sont pas variées et individuelles, et où ce n'est pas, dans une certaine mesure, une question d'opinion à laquelle choisir.


@sbi je ne suis pas sur le point de me lancer dans un autre débat stupide. Si vous avez une réponse basée sur des faits, allez-y et postez-le.


7 Réponses :


0
votes

Dans des situations rares mais heureuses, vous pouvez exploiter la nature à court-circuit de && et || : xxx

si vous devez Différencier entre une erreur dans la fonction 1 et 2, cela pourrait ne pas fonctionner si bien.

Esthétiquement, pas super beau mais c'est une manipulation des erreurs après tout :)


5 commentaires

Ok, c'est une option, mais j'essaie d'éviter de mettre l'appel dans une déclaration IF; Je trouve que cela a un effet quelque peu obscurci.


Hélas, qui exclut beaucoup de possibilités. Vous pouvez le macrocérez-le cependant. En outre, je vais avoir tiré pour ce commentaire, mais parfois goto aide aussi.


Personne ne devrait s'opposer à vous mentionner goto ... C'est une caractéristique moderne des langues de montage structurées modernes telles que C.


Alors, pouvez-vous élargir votre réponse pour suggérer un aller-goto -Based approche?


@Deadmg Vous avez peut-être manqué une discussion précédente (mod-supprimée) ici.



3
votes

Vous êtes confronté au fait que dans de nombreuses solutions aux problèmes, beaucoup de choses peuvent aller mal.

Manipulation de cette "erreur" -Situations fait partie de la solution au problème.

Donc, ma réponse est soit en train de résoudre des problèmes où rien (ni peu) ne peut échouer, ou prendre le fardeau d'accepter que les conditions d'erreur de traitement font partie de la solution .

SO (également) concevoir / écrire le code nécessaire pour traiter les échecs est un moyen essentiel de réussir.


En ce qui concerne les conseils pratiques: voir la manipulation des erreurs dans le cadre du code entier, car les erreurs manipulant les mêmes règles s'appliquent à chaque ligne de code:

  • facile à comprendre
  • assez strict pour être efficace
  • suffisamment flexible pour être étendu
  • échec de l'échec (redondant à mentionner dans ce contexte)
  • systématique / cohérent (en termes de motifs, de nommage, de mise en page)
  • documenté

    Constructions de langage possibles à utiliser:

    • pause s des contextes locaux
    • ( goto ) *
    • ( longjmp & amis pour "simuler" exceptions) *
    • Définition proprement définie (à nouveau systématique / cohérente) DÉCLARATIONS ET CODES DE RETOUR

      * à utiliser avec discipline de manière structurée.


5 commentaires

Utiliser LongJMP demande des problèmes.


@Catplusplus Si vous appelez vous-même un maître, vous pourrez gérer cela ... - mais vous avez raison, je n'aime pas l'utiliser. Trop stressé. Mais je ne pouvais pas résister à cela, après avoir écouté votre guerre ci-dessus ... ;-)


longjmp et goto pourrait être utilisé, s'il s'agit d'un codeur mature et discipliné .. ;-)


@alk Nombre même de page manuelle de LONDJMP dit que c'est mauvais et doit être évité. La maturité du codeur a absolument rien à faire avec le fait que toute l'idée derrière elle est mauvaise.


@Bartekbbanachewicz: je suis en désaccord - longjmp () remplit le vide entre codes d'état / errno et Quitter () / avortement () < / code> et devient particulièrement utile si les rappels sont impliqués



0
votes

Beaucoup des API Glib ont un gerror abstraction qui agit comme un type (explicite bien sûr, cela étant C) conteneur d'exception. Ou peut-être que errno abstraction est une meilleure description.

Il est utilisé comme un pointeur sur le pointeur, vous permettant de vérifier rapidement si un appel a réussi (une nouvelle gerror sera créée pour conserver toute erreur) et gérer des informations d'erreur détaillées en même temps. < / p>


1 commentaires

Je ne sais pas comment cela adresse ma question ... Sauf si vous ne suggère d'écrire des emballages avec ce type de titulaire d'exception?



0
votes

S'il y avait une solution à cela en C, les exceptions n'auraient pas été inventées. Vous n'avez que deux choix:

  • passer à une langue prenant en charge les exceptions.
  • pleurer sur les facteurs qui vous ont obligé à utiliser c et à écrire C, avec tous les problèmes inactifs.

    Bien que, si vous utilisez Visual C, vous pouvez utiliser SEH comme exceptions dans C. Ce n'est pas joli mais fonctionne.


1 commentaires

Je ne suis pas un grand fan de celui-ci, mais Go a une approche disciplinée de ce problème qui n'est pas basée sur des exceptions (à l'exception de certaines formes très restreintes de celle-ci).



3
votes

essayer d'aborder ce problème avec une sorte de curiosité scientifique. Il existe de nombreuses personnes qui affirment que l'approche de C sur la gestion des erreurs conduit à des programmeurs plus conscientes des conditions d'erreur, en accordant plus d'attention aux erreurs et où / comment ils devraient être traités. Considérez simplement cela un exercice (si un peu fastidieux) de sensibilisation, comme la méditation :)

Ne le combattez pas. Résolez cela autant que possible dans l'esprit de C et votre vision des choses se développera légèrement.

Consultez cet article sur c Erreur Mantring Mantra: http://tratt.net/laurie/ Tech_Articles / Articles / How_CAN_C_PROGRAMS_BE_SO_RelIable

Une réponse générale à votre question générale est: essayez de faire fonctionner les fonctions aussi petites que possible afin que vous puissiez revenir directement d'eux sur des erreurs. Cette approche est bonne dans toutes les langues. Le reste est un exercice dans le code de structuration.


4 commentaires

Lemme citez l'article que vous avez posté: (...) Il faut gérer toutes les chemins d'erreur possibles. C'est extrêmement douloureux (...)


@Bartekbanachewicz Pas de douleur, pas de gain: psychologyToday. Com / Blog / Memory-Medic / 201106 / ...


Pour être clair, je suis d'accord avec la conclusion de l'article: "Je ne recommande pas d'utiliser c sauf si beaucoup de pensée n'avait été donnée à la décision". J'aimerais ajouter: C ne produit pas de logiciels fiables, il produit des programmeurs fiables.


@Bartekbanachewicz qui est en effet la variante.



2
votes

Comme avec beaucoup de choses, la manipulation des erreurs en C nécessite plus de soins que dans les autres langues (de plus haut niveau).

Personnellement, je ne crois pas que c'est nécessairement une mauvaise chose car cela vous oblige à penser à l'erreur conditions, le flux de cotrol associé et vous aurez besoin de proposer un design approprié (car si vous ne le faites pas, le résultat sera probablement un désordre immunitaire). P>

grossièrement, vous pouvez diviser les conditions d'erreur Dans les catastrophes fatales et non fatales. P>

des non mortels, il y a ceux qui sont récupérables, c'est-à-dire que vous essayez à nouveau ou utilisez un mécanisme de secours. Ceux-ci, vous gérez normalement en ligne, même dans des langues qui appuient des exceptions. P>

Ensuite, il y en a ce que vous ne pouvez pas récupérer de. Au lieu de cela, vous voudrez peut-être enregistrer l'échec, mais en générant en informer l'appelant, par exemple via un code de retour ou une variable de type errno code>. Éventuellement, vous devrez peut-être faire un nettoyage dans la fonction, où un goto code> pourrait aider à structurer le code plus proprement. P>

des fatals, il y a ceux qui résilient la programme, c'est-à-dire que vous imprimez simplement un message d'erreur et Quitter () code> avec statut non zéro. p>

Ensuite, il y a des cas exceptionnels, où vous venez de vider le noyau (par exemple, via Abort () Code>). Les défaillances d'affirmation sont un sous-ensemble de ceux-ci, mais vous ne devez utiliser que assert () code> si la situation est censée être impossible pendant une exécution normale, votre code échoue toujours proprement sur ndebug code> constructions . P>

Une troisième classe d'exceptions mortelles est celles qui ne résolvent pas l'ensemble du programme, mais juste une chaîne d'appels (éventuellement profondément imbriquée). Vous pouvez utiliser longjmp () code> ici, mais vous devez prendre soin de nettoyer correctement les ressources telles que la mémoire allouée ou les descripteurs de fichiers, ce qui signifie que vous devez suivre ces ressources dans des pools. P>

Un peu de magie macro variable permet de proposer une belle syntaxe pendant au moins certains de ces cas, par exemple P>

_Bool do_stuff(int i);
do_stuff(i) || panic("failed to do stuff with %i", i);


0 commentaires

3
votes

Il existe de nombreuses façons d'obtenir une meilleure manipulation des erreurs. Tout dépend de ce que vous essayez de faire. Pour mettre en œuvre de nombreuses routines de manutention d'erreur pour appeler quelques fonctions ne vaudra pas la peine. Dans des bases de code plus grandes, vous pouvez le considérer.

Une meilleure manipulation des erreurs est le plus souvent obtenu en ajoutant plus de couches d'abstraction. Par exemple, si vous avez ces fonctions xxx

et une fonction de gestionnaire d'erreur: xxx

alors vous pourriez collecter des fonctions et les manipulateurs d'erreur ensemble. Soit en faisant un type de données basé sur la structure contenant une fonction et un gestionnaire d'erreur, puis effectuez une gamme de telles structures. Ou en faisant des tableaux individuels, accessibles à un index: xxx

une fois que vous avez ceci, vous pouvez afficher les appels de fonction dans une couche d'abstraction appropriée: < Pré> xxx

et ainsi de suite.


0 commentaires