2008-09-02 14 views
5

Ich arbeite an der Portierung einer Visual C++ - Anwendung auf GCC (sollte auf MingW und Linux aufbauen).Portable behandeln außergewöhnliche Fehler in C++

Der vorhandene Code verwendet __try { ... } __except(1) { ... } Blöcke an einigen Stellen, so dass fast nichts (kurz von möglicherweise nicht genügend Speichertyp Fehler?) Das Programm beenden würde, ohne einige minimale Protokollierung zu tun.

Was sind die Möglichkeiten, etwas Ähnliches mit GCC zu tun?

Bearbeiten: Danke für den Zeiger auf/EH-Optionen in Visual Studio, was ich jetzt brauche, ist einige Beispiele, wie Signale unter Linux zu behandeln sind. Ich habe this message von 2002 gefunden.

Welche anderen Signale außer SIGFPE und SIGSEVG sollte ich aufpassen? (Pflege vor allem über diejenigen, die von mich etwas falsch erhöht werden könnte)

Bounty Informationen: Ich möchte meine Anwendung in der Lage sein Selbst log so viele Fehlerbedingungen wie möglich, bevor es austritt.

Welche Signale könnte ich bekommen und in der Regel wäre es unmöglich, eine Fehlermeldung zu protokollieren? (Nicht genug Arbeitsspeicher, was sonst noch?)

Wie kann ich mit Ausnahmen umgehen und (am wichtigsten) Signale in einer tragbaren Weise, dass der Code zumindest das gleiche auf Linux und MingW funktioniert. #ifdef ist in Ordnung.

Der Grund, warum ich nicht nur einen Wrapper-Prozess haben, der den Fehler meldet, ist, dass ich aus Performancegründen bis zur letzten Minute, einige Daten auf dem Datenträger speichern zu schreiben, so dass, wenn etwas schief geht, ich will alle möglichen Versuche machen, zu schreiben die Daten vor dem Beenden aus.

Antwort

10

versuchen {xxx} catch (...) {xxx} wäre portabler, könnte aber nicht so viel fangen. Dies hängt von den Einstellungen und Umgebungen des Compilers ab.

Mithilfe der Standard-VC++ - Einstellungen werden asynchrone (SEH) Fehler nicht an die C++ EH-Infrastruktur übermittelt. Um sie zu fangen, müssen Sie stattdessen SEH-Handler verwenden (__try/__ außer). VC++ ermöglicht es Ihnen, SEH-Fehler durch C++ - Fehlerbehandlung zu leiten, wodurch ein Catch (...) SEH-Fehler abfangen kann; Dazu gehören Speicherfehler wie Nullzeigerdereferenzen. Details.

Unter Linux werden jedoch viele der Fehler, für die Windows SEH verwendet, durch Signale angezeigt. Diese werden niemals von try/catch gefangen; Um mit ihnen umgehen zu können, benötigen Sie einen Signalhandler.

0

Warum nicht die C++ - Standardausnahmen anstelle der proprietären MSFT-Erweiterung verwenden? C++ hat ein Ausnahmebehandlungskonzept.

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++ hat auch eine „Catch-All“ Klausel so, wenn Sie Ausnahmen protokollieren möchten Sie die folgende Wrapper verwenden:

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

Dies ist jedoch in C nicht sehr effizient ist ++, weil eine solche zu schaffen allgemeine Wrapper bedeutet, dass der Code für die Verarbeitung in alle nachfolgenden Stapelrahmen durch den Compiler eingefügt werden muss (anders als in verwalteten Systemen wie .NET, wo die Ausnahmebehandlung ohne zusätzliche Kosten kommt, solange keine Ausnahme ausgelöst wird).

+0

Das OP sucht nach Ausnahmebedingungen auf niedrigerer Ebene als C++ - Ausnahmen auf Sprachenebene. In einer POSIX-Welt bedeutet das, Signal-Handler für (fast) alles zu installieren. In MSVC behandelt der __try/__ catch-Mechanismus ähnliche Fehler (einschließlich des Win32-Äquivalents von SEGFAULT) –

+0

Richtig über die Fallen. Sie können MSVC jedoch so konfigurieren, dass SEH mit dem Standard "try"/"catch" abgefangen wird, wie von DrPizza ausgearbeitet. –

0

Für die Portabilität sollten Sie try-catch-Blöcke für die meisten Vanilla-Ausnahmen verwenden und dann einen terminate-Handler (set_terminate_handler) setzen, um einen minimalen Hook für katastrophale Beendigungsbedingungen zur Verfügung zu haben. Sie können auch versuchen, etwas wie einen atexit- oder on_exit-Handler hinzuzufügen. Ihre Ausführungsumgebung kann bizarr oder korrupt sein, wenn Sie diese Funktionen eingeben, also seien Sie vorsichtig, wie viel Sie von einer vernünftigen Umgebung erwarten.

Wenn schließlich regelmäßige try-catch-Paare verwenden, können Sie betrachten Blöcke mit der Funktion versuchen, im Gegensatz einen Try-Blockes in dem Körper einer Funktion zum Öffnen:

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

sie ein relativ unbekanntes Stück von C ist ++ und kann in einigen Fällen eine Wiederherstellung sogar im Falle einer partiellen (kleinen) Stapelkorruption bieten.

Schließlich wollen Sie wahrscheinlich herausfinden, welche Signale Sie selbstständig oder abbrechen können, und wenn Sie weniger Handhabungsmechanismen verwenden möchten, sollten Sie die Version ohne None verwenden des neuen Operators und Kompilieren, um bei Bedarf keine Gleitkommaausnahmen zu erzeugen (Sie können immer isenan (.), isfinite (.) auf FP-Ergebnissen prüfen, um sich zu schützen).

Auf diese letzte Anmerkung, sei vorsichtig: Ich habe festgestellt, dass die Gleitkomma-Ergebnisklassifizierungsfunktionen in verschiedenen Headern unter Linux und Windows sein können ... also müssen Sie diese Includes möglicherweise konditionieren.

Wenn Sie sich blöd fühlen, schreiben Sie alles mit setjmp und longjmp (das ist ein Witz ...).

-1

Ein Weg, der einfach zu verwenden, tragbar ist und kaum Ressourcen verwendet, wäre, leere Klassen zu fangen. Ich weiß, das mag zunächst komisch klingen, aber es kann sehr nützlich sein. Hier

ist ein Beispiel, das ich für eine andere Frage gestellt, die auch für Ihre Frage gilt: link

Sie können aber auch mehr als 1 Fang haben:

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 */ 
} 
0

Fangen C++ Ausnahmen mit catch(...) bereits bringt Sie in einer Twilight-Zone.

Der Versuch, Fehler zu erfassen, die nicht von catch(...) abgefangen werden, bringt Sie direkt in undefiniertes Verhalten. Kein C++ - Code funktioniert garantiert. Ihr minimaler Logging-Code kann dazu führen, dass die Rakete stattdessen startet.

Meine Empfehlung ist es, nicht einmal versuchen, catch(...). Fangen Sie nur Ausnahmen ab, die Sie sinnvoll und sicher protokollieren können, und lassen Sie das OS den Rest übernehmen, falls vorhanden.

Postmortem-Debugging wird hässlich, wenn Sie einen Fehler haben, der Code-Fehler zusätzlich zur eigentlichen Ursache behandelt.