C unterstützt keine Ausnahmebehandlung. Um eine Ausnahme in C auszulösen, müssen Sie etwas Plattformspezifisches wie die strukturierte Ausnahmebehandlung von Win32 verwenden. Um jedoch dabei zu helfen, müssen wir die Plattform kennen, die Sie interessiert.
Jerry Coffin
17
... und verwenden Sie keine strukturierte Win32-Ausnahmebehandlung.
Brian R. Bondy
3
Die Verwendung von setjmp () und longjmp () sollte theoretisch funktionieren, aber ich denke nicht, dass sich die Mühe lohnt.
Joseph Quinsey
Antworten:
75
In C gibt es keine Ausnahmen. In C werden die Fehler durch den zurückgegebenen Wert der Funktion, den Exit-Wert des Prozesses, Signale an den Prozess ( Program Error Signals (GNU libc) ) oder die Unterbrechung der CPU-Hardware (oder eine andere Benachrichtigung) benachrichtigt Fehler von der CPU, falls vorhanden) ( Wie der Prozessor den Fall der Division durch Null behandelt ).
Ausnahmen sind jedoch in C ++ und anderen Sprachen definiert. Die Ausnahmebehandlung in C ++ ist im C ++ - Standard "S.15 Ausnahmebehandlung" angegeben, es gibt keinen entsprechenden Abschnitt im C-Standard.
In C gibt es also garantiert keine Ausnahmen, wie?
httpinterpret
61
@httpinterpret: In C ist "garantiert", dass es keine Ausnahmen gibt, genauso wie "garantiert", dass es keine Vorlagen, keine Reflexion oder keine Einhörner gibt. Die Sprachspezifikation definiert so etwas einfach nicht. Es gibt jedoch setjmp / longjmp, mit dem eine Funktion beendet werden kann, ohne zurückzukehren. So könnten Programme ihre eigenen ausnahmeähnlichen Mechanismen erstellen, wenn sie dies wünschen, oder eine C-Implementierung könnte Erweiterungen des Standards definieren.
Steve Jessop
2
Ein Programm mit mainin einer .cDatei kann etwas C ++ enthalten, und daher können Ausnahmen im Programm ausgelöst und abgefangen werden, aber die C-Code-Teile wissen nichts davon, außer dass das Auslösen und Abfangen von Ausnahmen häufig von in C geschriebenen Funktionen abhängt die sich in den C ++ - Bibliotheken befinden. C wird verwendet, weil Sie nicht riskieren können, dass die aufgerufene Funktion throwselbst eine Ausnahme auslösen muss. Es kann jedoch einen Compiler / eine Bibliothek / ein Ziel geben, mit dem Ausnahmen ausgelöst / abgefangen werden können. Das Werfen einer Klasseninstanz hat jedoch eigene Probleme.
Strategie
61
@Steve: Bitte lassen Sie mich wissen, wenn Sie eine Sprache mit Einhörnern finden, ich habe jahrelang auf so etwas gewartet.
Brian R. Bondy
5
@ BrianR.Bondy Hier ist eine Sprache mit Einhörnern (ich garantiere es genauso wie es in C garantiert ist)
Tofandel
35
In C konnte man die Kombination der Verwendung setjmp()und longjmp()Funktionen, definiert in setjmp.h. Beispiel aus Wikipedia
#include<stdio.h>#include<setjmp.h>static jmp_buf buf;void second(void){
printf("second\n");// prints
longjmp(buf,1);// jumps back to where setjmp // was called - making setjmp now return 1}void first(void){
second();
printf("first\n");// does not print}int main(){if(! setjmp(buf)){
first();// when executed, setjmp returns 0}else{// when longjmp jumps back, setjmp returns 1
printf("main");// prints}return0;}
Hinweis: Ich würde Ihnen tatsächlich raten, sie nicht zu verwenden, da sie mit C ++ schrecklich funktionieren (Destruktoren lokaler Objekte würden nicht aufgerufen) und es wirklich schwer zu verstehen ist, was los ist. Geben Sie stattdessen einen Fehler zurück.
Ich habe gesehen, dass setjump / longjump in C ++ - Programmen nicht richtig funktioniert, selbst wenn keine Objekte zerstört wurden, wenn Ausnahmen verwendet wurden. Ich benutze sie selten in C-Programmen.
Strategie
Dies war ein interessanter Ansatz mit setjmp. on-time.com/ddj0011.htm Aber ja, im Grunde müssen Sie sie selbst erfinden, wenn Sie Out-of-Band-Code ausführen möchten, ohne den Stapel abzuwickeln.
Dwayne Robinson
Ich bin mir nicht sicher, warum die Einschränkung, sie in C ++ zu verwenden, wenn es um C geht, und C ++ sowieso Ausnahmen hat. In jedem Fall ist es wichtig , dass die OP weiß , dass in der Reihenfolge von der setjmp / longjmp Implementierung zu halten Ihr Bein schießen, immer daran denken , dass Sie zunächst notwendig , die Fehlerbehandlung (bis es einrichten), und dass Fehlerbehandlung zu besuchen muss zweimal zurückkehren.
1
Die Ausnahmebehandlung war übrigens etwas, von dem ich wirklich gehofft hatte, dass es in C11 gelandet wäre. Trotz allgemeiner Überzeugung ist OOP nicht erforderlich, um ordnungsgemäß zu funktionieren, und C leidet endlos unter jedem Funktionsaufruf, der eine erfordert if(). Ich kann keine Gefahr darin sehen; kann noch jemand hier?
@ user4229245 Ich habe den (anekdotischen) Eindruck, dass alles, was "für Sie getan" wurde, so weit wie möglich aus der c-Sprachspezifikation herausgehalten wird, um c für die Bare-Metal- und Maschinenprogrammierung relevant zu halten, wo selbst Status-Quo-Grundlagen wie 8-Bit-Bytes nicht vorhanden sind Nicht universell, nur meine Gedanken, ich bin kein C-Spec-Autor
ThorSummoner
21
Normales altes C unterstützt Ausnahmen nativ nicht.
Sie können alternative Fehlerbehandlungsstrategien verwenden, z.
Rückgabe eines Fehlercodes
Rückgabe FALSEund Verwendung einer last_errorVariablen oder Funktion.
Auch Windows API hat die gleiche Methode, um die Fehler zu behandeln. Zum Beispiel GetLastError()in der Windows-API.
BattleTested
20
In C gibt es keinen integrierten Ausnahmemechanismus. Sie müssen Ausnahmen und deren Semantik simulieren . Dies wird normalerweise erreicht, indem man sich auf setjmpund verlässt longjmp.
Es gibt einige Bibliotheken, und ich implementiere noch eine. Es heißt Ausnahmen4c ; Es ist tragbar und kostenlos. Sie können es sich ansehen und es mit anderen Alternativen vergleichen, um herauszufinden , welche am besten zu Ihnen passt.
Ich habe Ihr Codebeispiel gelesen und ein ähnliches Projekt mit einer Struktur gestartet, aber eine UUID anstelle einer Zeichenfolge verwendet, um jede "Ausnahme" zu identifizieren. Ihr Projekt scheint sehr vielversprechend.
Kennen Sie (oder jemand anderes) einen Vergleich zwischen den verschiedenen Ausnahmepaketen?
Marcel Waldvogel
11
C kann eine C ++ - Ausnahme auslösen, es handelt sich sowieso um Maschinencodes. Zum Beispiel in bar.c.
// begin bar.c#include<stdlib.h>#include<stdint.h>externvoid*__cxa_allocate_exception(size_t thrown_size);externvoid __cxa_throw (void*thrown_exception,void**tinfo,void(*dest)(void*));externvoid*_ZTIl;// typeinfo of longint bar1(){int64_t* p =(int64_t*)__cxa_allocate_exception(8);*p =1976;
__cxa_throw(p,&_ZTIl,0);return10;}// end bar.c
Was zum Teufel ist "_ZTIl" ??? Ich kann nirgendwo einen Verweis darauf finden und es ist ein völliges Rätsel, wie es C-Code ermöglichen würde, auf std :: type_info zuzugreifen. Bitte hilf mir!
AreusAstarte
1
_ZTIIbedeutet typeinfo for longz echo '_ZTIl' | c++filt . Es ist das g ++ Mangling-Schema.
wcy
und nur zum guten Teil sollten Sie das AC-Symbol im Catch-Block aufrufen, um c ++ so weit wie möglich zu vermeiden: P (PS, danke, dass Sie ein hervorragendes Beispiel gegeben haben!)
ThorSummoner
8
Diese Frage ist super alt, aber ich bin nur darauf gestoßen und dachte, ich würde eine Technik teilen: durch Null teilen oder einen Nullzeiger dereferenzieren.
Die Frage ist einfach "wie man wirft", nicht wie man fängt oder sogar wie man eine bestimmte Art von Ausnahme wirft. Ich hatte vor Ewigkeiten eine Situation, in der wir eine Ausnahme von C auslösen mussten, um in C ++ abgefangen zu werden. Insbesondere hatten wir gelegentlich Berichte über "reine virtuelle Funktionsaufruf" -Fehler und mussten die _purecall-Funktion der C-Laufzeit davon überzeugen, etwas auszulösen. Also haben wir unsere eigene _purecall-Funktion hinzugefügt, die durch Null geteilt wird, und boom. Wir haben eine Ausnahme bekommen, die wir in C ++ abfangen und sogar etwas Stapelspaß verwenden können, um zu sehen, wo etwas schief gelaufen ist.
@AreusAstarte nur für den Fall, dass jemandem wirklich eine C-Division durch Null gezeigt werden muss:int div_by_nil(int x) { return x/0; }
7
Bei Win mit MSVC gibt es __try ... __except ...aber es ist wirklich schrecklich und Sie möchten es nicht verwenden, wenn Sie es möglicherweise vermeiden können. Besser zu sagen, dass es keine Ausnahmen gibt.
Wie in zahlreichen Threads erwähnt, ist die "Standard" -Methode dazu die Verwendung von setjmp / longjmp. Ich habe eine weitere solche Lösung unter https://github.com/psevon/exceptions-and-raii-in-c veröffentlicht.
Dies ist meines Wissens die einzige Lösung, die auf der automatischen Bereinigung der zugewiesenen Ressourcen beruht. Es implementiert eindeutige und gemeinsam genutzte Smartpointers und ermöglicht Zwischenfunktionen, Ausnahmen durchzulassen, ohne sie abzufangen, und ihre lokal zugewiesenen Ressourcen weiterhin ordnungsgemäß zu bereinigen.
C unterstützt keine Ausnahmen. Sie können versuchen, Ihren C-Code mit Visual Studio oder G ++ als C ++ zu kompilieren und prüfen, ob er unverändert kompiliert wird. Die meisten C-Anwendungen werden ohne größere Änderungen als C ++ kompiliert, und Sie können dann die Syntax try ... catch verwenden.
Wenn Sie Code mit dem Happy Path-Entwurfsmuster (dh für eingebettete Geräte) schreiben, können Sie die Verarbeitung von Ausnahmefehlern (auch bekannt als Deffering oder endgültige Emulation) mit dem Operator "goto" simulieren.
int process(int port){int rc;int fd1;int fd2;
fd1 = open("/dev/...",...);if(fd1 ==-1){
rc =-1;goto out;}
fd2 = open("/dev/...",...);if(fd2 ==-1){
rc =-1;goto out;}// Do some with fd1 and fd2 for example write(f2, read(fd1))
rc =0;
out://if (rc != 0) {(void)close(fd1);(void)close(fd2);//}return rc;}
Es ist eigentlich kein Ausnahmebehandler, aber es bietet Ihnen eine Möglichkeit, Fehler beim Beenden der Funktion zu behandeln.
PS Sie sollten vorsichtig sein, wenn Sie nur aus denselben oder mehreren tieferen Bereichen gehen und niemals die Variablendeklaration überspringen.
Antworten:
In C gibt es keine Ausnahmen. In C werden die Fehler durch den zurückgegebenen Wert der Funktion, den Exit-Wert des Prozesses, Signale an den Prozess ( Program Error Signals (GNU libc) ) oder die Unterbrechung der CPU-Hardware (oder eine andere Benachrichtigung) benachrichtigt Fehler von der CPU, falls vorhanden) ( Wie der Prozessor den Fall der Division durch Null behandelt ).
Ausnahmen sind jedoch in C ++ und anderen Sprachen definiert. Die Ausnahmebehandlung in C ++ ist im C ++ - Standard "S.15 Ausnahmebehandlung" angegeben, es gibt keinen entsprechenden Abschnitt im C-Standard.
quelle
main
in einer.c
Datei kann etwas C ++ enthalten, und daher können Ausnahmen im Programm ausgelöst und abgefangen werden, aber die C-Code-Teile wissen nichts davon, außer dass das Auslösen und Abfangen von Ausnahmen häufig von in C geschriebenen Funktionen abhängt die sich in den C ++ - Bibliotheken befinden. C wird verwendet, weil Sie nicht riskieren können, dass die aufgerufene Funktionthrow
selbst eine Ausnahme auslösen muss. Es kann jedoch einen Compiler / eine Bibliothek / ein Ziel geben, mit dem Ausnahmen ausgelöst / abgefangen werden können. Das Werfen einer Klasseninstanz hat jedoch eigene Probleme.In C konnte man die Kombination der Verwendung
setjmp()
undlongjmp()
Funktionen, definiert insetjmp.h
. Beispiel aus WikipediaHinweis: Ich würde Ihnen tatsächlich raten, sie nicht zu verwenden, da sie mit C ++ schrecklich funktionieren (Destruktoren lokaler Objekte würden nicht aufgerufen) und es wirklich schwer zu verstehen ist, was los ist. Geben Sie stattdessen einen Fehler zurück.
quelle
if()
. Ich kann keine Gefahr darin sehen; kann noch jemand hier?Normales altes C unterstützt Ausnahmen nativ nicht.
Sie können alternative Fehlerbehandlungsstrategien verwenden, z.
FALSE
und Verwendung einerlast_error
Variablen oder Funktion.Siehe http://en.wikibooks.org/wiki/C_Programming/Error_handling .
quelle
GetLastError()
in der Windows-API.In C gibt es keinen integrierten Ausnahmemechanismus. Sie müssen Ausnahmen und deren Semantik simulieren . Dies wird normalerweise erreicht, indem man sich auf
setjmp
und verlässtlongjmp
.Es gibt einige Bibliotheken, und ich implementiere noch eine. Es heißt Ausnahmen4c ; Es ist tragbar und kostenlos. Sie können es sich ansehen und es mit anderen Alternativen vergleichen, um herauszufinden , welche am besten zu Ihnen passt.
quelle
C kann eine C ++ - Ausnahme auslösen, es handelt sich sowieso um Maschinencodes. Zum Beispiel in bar.c.
in a.cc,
um es zu kompilieren
Ausgabe
http://mentorembedded.github.io/cxx-abi/abi-eh.html enthält weitere Informationen zu
__cxa_throw
.Ich bin nicht sicher, ob es portabel ist oder nicht, und ich teste es mit 'gcc-4.8.2' unter Linux.
quelle
_ZTII
bedeutettypeinfo for long
zecho '_ZTIl' | c++filt
. Es ist das g ++ Mangling-Schema.Diese Frage ist super alt, aber ich bin nur darauf gestoßen und dachte, ich würde eine Technik teilen: durch Null teilen oder einen Nullzeiger dereferenzieren.
Die Frage ist einfach "wie man wirft", nicht wie man fängt oder sogar wie man eine bestimmte Art von Ausnahme wirft. Ich hatte vor Ewigkeiten eine Situation, in der wir eine Ausnahme von C auslösen mussten, um in C ++ abgefangen zu werden. Insbesondere hatten wir gelegentlich Berichte über "reine virtuelle Funktionsaufruf" -Fehler und mussten die _purecall-Funktion der C-Laufzeit davon überzeugen, etwas auszulösen. Also haben wir unsere eigene _purecall-Funktion hinzugefügt, die durch Null geteilt wird, und boom. Wir haben eine Ausnahme bekommen, die wir in C ++ abfangen und sogar etwas Stapelspaß verwenden können, um zu sehen, wo etwas schief gelaufen ist.
quelle
int div_by_nil(int x) { return x/0; }
Bei Win mit MSVC gibt es
__try ... __except ...
aber es ist wirklich schrecklich und Sie möchten es nicht verwenden, wenn Sie es möglicherweise vermeiden können. Besser zu sagen, dass es keine Ausnahmen gibt.quelle
C hat keine Ausnahmen.
Es gibt verschiedene hackige Implementierungen, die dies versuchen (ein Beispiel unter: http://adomas.org/excc/ ).
quelle
Wie in zahlreichen Threads erwähnt, ist die "Standard" -Methode dazu die Verwendung von setjmp / longjmp. Ich habe eine weitere solche Lösung unter https://github.com/psevon/exceptions-and-raii-in-c veröffentlicht. Dies ist meines Wissens die einzige Lösung, die auf der automatischen Bereinigung der zugewiesenen Ressourcen beruht. Es implementiert eindeutige und gemeinsam genutzte Smartpointers und ermöglicht Zwischenfunktionen, Ausnahmen durchzulassen, ohne sie abzufangen, und ihre lokal zugewiesenen Ressourcen weiterhin ordnungsgemäß zu bereinigen.
quelle
C unterstützt keine Ausnahmen. Sie können versuchen, Ihren C-Code mit Visual Studio oder G ++ als C ++ zu kompilieren und prüfen, ob er unverändert kompiliert wird. Die meisten C-Anwendungen werden ohne größere Änderungen als C ++ kompiliert, und Sie können dann die Syntax try ... catch verwenden.
quelle
Wenn Sie Code mit dem Happy Path-Entwurfsmuster (dh für eingebettete Geräte) schreiben, können Sie die Verarbeitung von Ausnahmefehlern (auch bekannt als Deffering oder endgültige Emulation) mit dem Operator "goto" simulieren.
Es ist eigentlich kein Ausnahmebehandler, aber es bietet Ihnen eine Möglichkeit, Fehler beim Beenden der Funktion zu behandeln.
PS Sie sollten vorsichtig sein, wenn Sie nur aus denselben oder mehreren tieferen Bereichen gehen und niemals die Variablendeklaration überspringen.
quelle