Question

Je travaille sur le portage d'une application Visual C++ vers GCC (devrait s'appuyer sur MingW et Linux).

Le code existant utilise __try { ... } __except(1) { ... } bloque à quelques endroits afin que presque rien (à part peut-être des erreurs de type mémoire insuffisante ?) ne fasse se terminer le programme sans effectuer une journalisation minimale.

Quelles sont les options pour faire quelque chose de similaire avec GCC ?

Modifier:Merci pour le pointeur vers les options /EH dans Visual Studio, j'ai maintenant besoin de quelques exemples sur la façon de gérer les signaux sous Linux.J'ai trouvé ce message à partir de 2002.

Quels autres signaux en plus SIGFPE et SIGSEVG dois-je faire attention ?(Je me soucie surtout de ceux qui pourraient être élevés à partir de moi faire quelque chose de mal)

Informations sur la prime:Je souhaite que mon application puisse enregistrer automatiquement autant de conditions d'erreur que possible avant de se terminer.

Quels signaux puis-je recevoir et après lesquels il serait généralement impossible d'enregistrer un message d'erreur ?(Je n'ai plus de mémoire, quoi d'autre ?)

Comment puis-je gérer les exceptions et (surtout) les signaux de manière portable indiquant que le code fonctionne au moins de la même manière sous Linux et MingW.#ifdef est OK.

La raison pour laquelle je n'ai pas seulement un processus wrapper qui enregistre l'échec est que, pour des raisons de performances, j'enregistre l'écriture de certaines données sur le disque jusqu'à la dernière minute, donc si quelque chose ne va pas, je veux faire toutes les tentatives possibles pour écrire les données avant sortir.

Était-ce utile?

La solution

try { xxx } catch(...) { xxx } serait plus portable mais pourrait ne pas en attraper autant.Cela dépend des paramètres et des environnements du compilateur.

Grâce aux paramètres VC++ par défaut, les erreurs asynchrones (SEH) ne sont pas transmises à l'infrastructure C++ EH ;pour les attraper, vous devez plutôt utiliser les gestionnaires SEH (__try/__sauf).VC++ vous permet d'acheminer les erreurs SEH via la gestion des erreurs C++, ce qui permet à un catch(...) de piéger les erreurs SEH ;cela inclut les erreurs de mémoire telles que les déréférencements de pointeurs nuls. Détails.

Sous Linux, cependant, la plupart des erreurs pour lesquelles Windows utilise SEH sont indiquées par des signaux.Ceux-ci ne sont jamais capturés par try/catch ;pour les gérer, vous avez besoin d'un gestionnaire de signaux.

Autres conseils

Pourquoi ne pas utiliser les exceptions standard C++ au lieu de l'extension propriétaire de MSFT ?C++ a un concept de gestion des exceptions.

struct my_exception_type : public logic_error {
    my_exception_type(char const* msg) : logic_error(msg) { }
};

try {
    throw my_exception_type("An error occurred");
} catch (my_exception_type& ex) {
    cerr << ex.what << endl;
}

C++ a également une clause « catchall », donc si vous souhaitez enregistrer les exceptions, vous pouvez utiliser le wrapper suivant :

try {
    // …
}
catch (...) {
}

Cependant, cela n'est pas très efficace en C++ car la création d'un tel wrapper général signifie que le code de gestion doit être inséré dans chaque cadre de pile ultérieur par le compilateur (contrairement aux systèmes gérés comme .NET où la gestion des exceptions n'entraîne aucun coût supplémentaire tant qu'aucune exception n'est réellement levée).

Pour la portabilité, une chose à essayer est d'utiliser des blocs try-catch pour la plupart des exceptions Vanilla, puis de définir un gestionnaire de fin (set_terminate_handler) pour avoir un hook minimal disponible pour les conditions de sortie catastrophiques.Vous pouvez également essayer d'ajouter quelque chose comme un gestionnaire atexit ou on_exit.Votre environnement d'exécution peut bien sûr être bizarre ou corrompu lorsque vous entrez dans ces fonctions, alors faites attention à ce que vous présumez d'un environnement sain.

Enfin, lorsque vous utilisez des paires try-catch régulières, vous pouvez envisager d'utiliser des blocs try de fonction plutôt que d'ouvrir un bloc try dans le corps d'une fonction :

int foo(int x) try {
  // body of foo
} catch (...) {
   // be careful what's done here!
}

il s'agit d'une partie relativement inconnue du C++ et peut dans certains cas offrir une récupération même en cas de corruption partielle (à petite échelle) de la pile.

Enfin, oui, vous souhaiterez probablement rechercher quels signaux vous pouvez continuellement gérer vous-même ou sur lesquels vous pourriez abandonner, et si vous souhaitez moins de mécanismes de gestion en place, vous pouvez envisager d'appeler la version sans lancement du nouvel opérateur. , et compiler pour ne pas générer d'exceptions à virgule flottante si nécessaire (vous pouvez toujours vérifier isnan(.), isfinite(.), sur les résultats FP pour vous protéger).

Sur cette dernière note, soyez prudent :J'ai remarqué que les fonctions de classification des résultats en virgule flottante peuvent se trouver dans différents en-têtes sous Linux et Windows...vous devrez donc peut-être conditionner ces inclusions.

Si vous vous sentez malicieux, écrivez tout en utilisant setjmp et longjmp (c'est une blague...).

Détecter les exceptions C++ avec catch(...) vous met déjà dans une zone crépusculaire.

Essayer de détecter les erreurs non détectées par catch(...) vous met carrément dans un comportement indéfini.Aucun code C++ n'est garanti de fonctionner.Votre code de journalisation minimal peut provoquer le lancement du missile à la place.

Ma recommandation est de ne même pas essayer de catch(...).N'interceptez que les exceptions que vous pouvez enregistrer de manière significative et en toute sécurité et laissez le système d'exploitation gérer le reste, le cas échéant.

Le débogage post-mortem devient moche si vous rencontrez des échecs de code de gestion des erreurs en plus de la cause première.

Une méthode facile à utiliser, portable et utilisant à peine des ressources serait d'attraper des classes vides.Je sais que cela peut paraître étrange au début, mais cela peut être très utile.

Voici un exemple que j'ai fait pour une autre question qui s'applique également à votre question : lien

De plus, vous pouvez avoir plus d'une capture :

try
{
   /* code that may throw exceptions */
}
catch (Error1 e1)
{
   /* code if Error1 is thrown */
}
catch (Error2 e2)
{
   /* code if Error2 is thrown */
}
catch (...)
{
   /* any exception that was not expected will be caught here */
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top