Was passiert, wenn eine Ausnahme “durch” C-Code geworfen wird? [duplicate]

Lesezeit: 9 Minuten

Benutzer-Avatar
Jochen_0x90h

Mögliches Duplikat:

Werden C++-Ausnahmen sicher durch C-Code weitergegeben?

Wenn Sie C-Code haben, zum Beispiel die png-lib, mit Ihren eigenen io-Handlern, die in c++ geschrieben sind, und aufgrund eines io-Fehlers eine Ausnahme ausgelöst wird. Ist es in Ordnung, es durch den C-Code laufen zu lassen und es außerhalb des C-Codes abzufangen? Ich weiß, dass bei Speicherlecks Vorsicht geboten ist, aber normalerweise werden alle Strukturen vorab zugewiesen.

  • Wenn Sie eine C-Bibliothek verwenden möchten, die Ihren C++-Rückruf aufruft, in dem Sie eine Ausnahme auslösen, und sicherstellen, dass Sie sie irgendwo in Ihrem eigenen Code abfangen, können Sie die Ausnahmebehandlung in GCC mit aktivieren -fexceptions beim Kompilieren Ihrer C-Bibliothek und es sollte funktionieren.

    – Kerrek SB

    21. Juni 2011 um 14:24 Uhr

  • Ich denke, dies ruft undefiniertes Verhalten hervor. Das Allermindeste ist, dass C-Code nicht ausnahmesicher ist, sodass Ressourcen links und rechts verloren gehen. Siehe auch diese Antwort: stackoverflow.com/questions/6253574/…

    – sbi

    21. Juni 2011 um 14:31 Uhr


  • +1 für die einzige Frage, die ich bisher gesehen habe und die beide rechtmäßig verwenden kann [c] und [c++] Stichworte.

    – Justin ᚅᚔᚈᚄᚒᚔ

    21. Juni 2011 um 14:41 Uhr

  • @sbi: Sicher, Sie würden die volle Verantwortung für die Fehler des C-Codes übernehmen, sollte eine Ausnahme auftreten. Ich denke, es ist nur für seltsame Szenarien, in denen Sie wirklich Ihre eigene C-Bibliothek für andere Zwecke schreiben möchten, aber auch C ++ – Funktionen durch sie hindurchleiten möchten und alles unter Ihrer Kontrolle liegt …

    – Kerrek SB

    21. Juni 2011 um 14:50 Uhr

  • @Kerrek: Aber es ist nicht unter deiner Kontrolle. Es gibt keine Möglichkeit, sich selbst im C-Code zu bereinigen, wenn C++-Ausnahmen vorbeirauschen. In C fehlen Ihnen dazu die Werkzeuge. Deshalb gibt es auf solche Fragen nur eine legitime Antwort: Lassen Sie keine C++-Ausnahmen durch Code in anderen Sprachen passieren, sei es C oder irgendetwas anderes.

    – sbi

    21. Juni 2011 um 14:57 Uhr

Es liegt ganz beim Compiler, ob dies funktioniert oder nicht. Offensichtlich kann keiner der Sprachstandards etwas darüber aussagen, was die andere Sprache tun soll.

Im besten Fall übergibt die Ausnahme den C-Code und kehrt zur nächsten C++-Ebene zurück, während möglicherweise dynamisch zugewiesene C-Strukturen verloren gehen. Im weniger guten Fall wird es abstürzen und brennen!

Eine Möglichkeit besteht natürlich darin, den C-Code als C++ zu kompilieren und gleichzeitig zu prüfen, ob er ausnahmeneutral ist.

  • Der Sprachstandard kann nicht sagen, was andere Sprachen tun sollten, aber sie kann sagen was die Implementierung tun sollte, und dazu gehört auch die sprachunabhängige Laufzeitumgebung ABI. Zumindest könnte der Standard dieses implementierungsdefinierte Verhalten vornehmen.

    – Kyle Strand

    23. April 2019 um 19:05 Uhr

Benutzer-Avatar
Nemo

Die Antwort auf Ihre Frage ist implementierungsabhängig.

Für GCC, wie @Kerrek sagt, kompilieren Sie den C-Code mit -fexceptions stellt sicher, dass die Laufzeit konsistent bleibt, wenn eine Ausnahme durch C-Code ausgelöst wird. (Beachten Sie, dass moderne Ausnahmemechanismen nicht gerade über setjmp/longjmp implementiert; Sie wickeln den Stapel Frame für Frame ab, um mit Destruktoren umzugehen und Blöcke richtig zu versuchen/abzufangen.)

Der C-Code selbst erwartet jedoch möglicherweise nicht, dass Ausnahmen durch ihn geworfen werden. Viele C-Codes sind so geschrieben:

acquire a resource
do some stuff
release resource

Hier könnte “eine Ressource erwerben” bedeuten mallocoder pthread_mutex_lockoder fopen. Wenn Ihr C++-Code Teil von “do some stuff” ist und eine Ausnahme auslöst, nun ja … Whoops.

Ressourcenlecks sind nicht das einzige Problem; so ist Korrektheit allgemein. Vorstellen:

subtract $100 from savings account
add $100 to checking account

Stellen Sie sich nun vor, dass eine Ausnahme ausgelöst wird, nachdem der erste Schritt abgeschlossen ist, aber bevor der zweite dies tut.

Kurz gesagt, obwohl Ihre Implementierung möglicherweise eine Möglichkeit bietet, Ausnahmen durch C-Code auszulösen, ist dies eine schlechte Idee, es sei denn, Sie haben diesen C-Code auch so geschrieben, dass Sie genau wissen, wo eine Ausnahme ausgelöst werden könnte.

  • Etwas spät, aber dein Banking-Beispiel ist nicht sehr gut, da du solche Sachen sowieso nicht machen willst. Sie möchten Transaktionen verwenden, damit Sie Zustände jederzeit rückgängig machen können. Was bedeutet, dass die subtract ist nichts, sondern ein vorübergehender Zustand und stellt daher kein wirkliches Problem dar, da Sie die Subtraktionen einfach rückgängig machen können. Jetzt wird Ihr Beispiel in die reale Situation gebracht.

    – Bauss

    31. Januar 2017 um 13:15 Uhr


  • Ich danke dir sehr. Dies war die Antwort, die die Frage löste: “Können Sie eine Ausnahme von Ihrem Hauptprogramm über eine in C geschriebene gemeinsam genutzte Bibliothek auslösen und sie in Ihrem Hauptprogramm erneut abfangen?” – Ja, du kannst!

    – gonzo

    26. Dezember 2020 um 1:08 Uhr

Es ist in Ordnung für Ihren C++-Code, wenn es so ist:

  1. Mit aktivierten Ausnahmen kompiliert.
  2. Ausnahme sicher.

Für Ihren C- oder C++-Code ist es in Ordnung, wenn:

  1. Zwischen dem Auslösen der Ausnahme und ihrem Abfangen müssen keine Ressourcen explizit gesammelt werden.

Code, der mit C++-Ausnahmeunterstützung kompiliert wurde, fügt spezielle Hooks hinzu, um zu bereinigen, wenn Ausnahmen ausgelöst und nicht in diesem Bereich abgefangen werden. Auf dem Stack zugewiesene C++-Objekte haben ihre Destruktoren aufgerufen.

Die einzige Ressource, die in C (oder C++ ohne Ausnahmeunterstützung) zurückgefordert wird, wenn eine Ausnahme ausgelöst wird, ist der Speicherplatz, der in jedem Stapelrahmen zugewiesen ist.

Diese Abteilung des GCC-Handbuchs ist sehr hilfreich:

       -fexceptions
           Enable exception handling.  Generates extra code needed to
           propagate exceptions.  For some targets, this implies GCC will
           generate frame unwind information for all functions, which can
           produce significant data size overhead, although it does not affect
           execution.  If you do not specify this option, GCC will enable it
           by default for languages like C++ which normally require exception
           handling, and disable it for languages like C that do not normally
           require it.  However, you may need to enable this option when
           compiling C code that needs to interoperate properly with exception
           handlers written in C++.  You may also wish to disable this option
           if you are compiling older C++ programs that don't use exception
           handling.

  • Ihr C-Code kann Ressourcen enthalten, wenn Ihr Code vor der Rückkehr eine Ressourcenzuweisungsfunktion im Destruktor einer RAII-Klasse am letzten Punkt Ihres C++-Codes aufruft. Das macht die libjpeg-API. Wenn die Laufzeit feststellt, dass die Ausnahme abgefangen wird, werden die C++-Stack-Frames abgewickelt, und wenn der letzte abgewickelt wird, wird der Fehlerrückruf aufgerufen, wodurch alle C-Ressourcen freigegeben und der Status zurückgesetzt wird. Dann übergibt die Ausnahme den C-Code, der in C++ landet, um mit dem Abwickeln fortzufahren . Alles wie man es sich wünscht.

    – Codeschuss

    19. Oktober 2017 um 23:29 Uhr

Ausnahmen werden normalerweise nicht wirklich “durch” Code geworfen; Wie die Aktion impliziert, werden sie “über” Code geworfen.

Als Beispiel; zumindest Objective-C-Ausnahmen der alten Schule werden normalerweise mit setjmp und longjmp implementiert; im Wesentlichen Speichern der Adressen des Codes für die spätere Verwendung.

Es ist sinnvoll, C++-Ausnahmen mit ähnlichen Mechanismen zu implementieren; und als solche; Die Art des Codes, durch den die Ausnahme geworfen wird, oder genauer gesagt, “über” spielt keine Rolle, wenn überhaupt. Man könnte sich sogar eine Einstellung vorstellen, bei der eine Objective-C-Ausnahme über einen C++-Catch geworfen wird oder umgekehrt.

Bearbeiten: Wie Bo Persson erwähnt; das soll nicht heißen, dass eine C++-Ausnahme, die den C-Code unterbricht, nicht Chaos und Lecks verursachen würde; aber das Auslösen von Ausnahmen ist normalerweise rundum eine schlechte Sache™; also wird es wahrscheinlich nicht viel ausmachen.

PS: Kudos, dass Sie tatsächlich eine Frage gestellt haben, bei der die Verwendung von C- und C++-Tags relevant ist. 😉

C weiß nichts über Ausnahmen, daher ist es nicht möglich zu sagen, was passieren würde.

Um konformen Code zu schreiben, müssten Sie Ausnahmen abfangen, bevor Sie in die C-Bibliothek zurückkehren, in Fehlercodes übersetzen und dann den C-Bibliotheksfehler am anderen Ende wieder in eine Ausnahme übersetzen.

  • “Weiß nicht” ist nicht wirklich der Grund für das Verhalten.

    – Matt Tischler

    21. Juni 2011 um 14:31 Uhr

  • @Matt: aber es ist der Grund dafür, dass man nicht sagen kann, was passieren würde.

    – Dennis Zickefoose

    21. Juni 2011 um 16:29 Uhr

  • Ich erinnere mich, dass die GCC-ABI definiert, dass die Ausnahme direkt über dem Kopf von C liegt, obwohl ich keine Referenz für dieses Detail mehr finden kann, und ich fand diesen “C-Sprachcode, der erwartet, mit C++ zu interagieren, sollte mit -fExceptions kompiliert werden. Dies wird machen Debuggen einer C-Sprachfunktion, die als Teil des C++-induzierten Stack-Unwinding aufgerufen wird, möglich. Insbesondere führt das Unwinding in einen Frame ohne Ausnahmebehandlungsdaten zu einem Laufzeitabbruch. Wenn dem Unwinder die Unwind-Informationen ausgehen, bevor er einen Handler findet, std: :terminate() wird aufgerufen.”

    – Codeschuss

    19. Oktober 2017 um 23:36 Uhr

  • Infolgedessen erlaube ich C++-Ausnahmen, direkt über libjpeg zu gehen, um die Informationen über die Throw-Site an allen Punkten zu maximieren, und ich rufe den JPEG-Fehler-Callback im Destruktor einer RAII-Klasse im C++-Callback auf, um alle Ressourcen von C freizugeben. Ich hatte keine Debugging-Probleme.

    – Codeschuss

    19. Oktober 2017 um 23:38 Uhr

  • für GCC auf x86-64 ist die Dokumentation falsch. -fno-asynchronous-unwind-tables ist erforderlich, um in dieser Situation einen Abbruch zu bewirken.

    – Codeschuss

    20. Oktober 2017 um 0:14 Uhr

  • “Weiß nicht” ist nicht wirklich der Grund für das Verhalten.

    – Matt Tischler

    21. Juni 2011 um 14:31 Uhr

  • @Matt: aber es ist der Grund dafür, dass man nicht sagen kann, was passieren würde.

    – Dennis Zickefoose

    21. Juni 2011 um 16:29 Uhr

  • Ich erinnere mich, dass die GCC-ABI definiert, dass die Ausnahme direkt über dem Kopf von C liegt, obwohl ich keine Referenz für dieses Detail mehr finden kann, und ich fand diesen “C-Sprachcode, der erwartet, mit C++ zu interagieren, sollte mit -fExceptions kompiliert werden. Dies wird machen Debuggen einer C-Sprachfunktion, die als Teil des C++-induzierten Stack-Unwinding aufgerufen wird, möglich. Insbesondere führt das Unwinding in einen Frame ohne Ausnahmebehandlungsdaten zu einem Laufzeitabbruch. Wenn dem Unwinder die Unwind-Informationen ausgehen, bevor er einen Handler findet, std: :terminate() wird aufgerufen.”

    – Codeschuss

    19. Oktober 2017 um 23:36 Uhr

  • Infolgedessen erlaube ich C++-Ausnahmen, direkt über libjpeg zu gehen, um die Informationen über die Throw-Site an allen Punkten zu maximieren, und ich rufe den JPEG-Fehler-Callback im Destruktor einer RAII-Klasse im C++-Callback auf, um alle Ressourcen von C freizugeben. Ich hatte keine Debugging-Probleme.

    – Codeschuss

    19. Oktober 2017 um 23:38 Uhr

  • für GCC auf x86-64 ist die Dokumentation falsch. -fno-asynchronous-unwind-tables ist erforderlich, um in dieser Situation einen Abbruch zu bewirken.

    – Codeschuss

    20. Oktober 2017 um 0:14 Uhr

1367020cookie-checkWas passiert, wenn eine Ausnahme “durch” C-Code geworfen wird? [duplicate]

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy