Ich habe dies in Google eingegeben, aber nur in C ++ Howtos gefunden.
wie geht das in C?
Ich habe dies in Google eingegeben, aber nur in C ++ Howtos gefunden.
wie geht das in C?
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.
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 Funktion throw
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()
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
}
return 0;
}
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.
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 einer last_error
Variablen oder Funktion.Siehe http://en.wikibooks.org/wiki/C_Programming/Error_handling .
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ä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.
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>
extern void *__cxa_allocate_exception(size_t thrown_size);
extern void __cxa_throw (void *thrown_exception, void* *tinfo, void (*dest) (void *) );
extern void * _ZTIl; // typeinfo of long
int bar1()
{
int64_t * p = (int64_t*)__cxa_allocate_exception(8);
*p = 1976;
__cxa_throw(p,&_ZTIl,0);
return 10;
}
// end bar.c
in a.cc,
#include <stdint.h>
#include <cstdio>
extern "C" int bar1();
void foo()
{
try{
bar1();
}catch(int64_t x){
printf("good %ld",x);
}
}
int main(int argc, char *argv[])
{
foo();
return 0;
}
um es zu kompilieren
gcc -o bar.o -c bar.c && g++ a.cc bar.o && ./a.out
Ausgabe
good 1976
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.
_ZTII
bedeutet typeinfo for long
z echo '_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.
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.
C hat keine Ausnahmen.
Es gibt verschiedene hackige Implementierungen, die dies versuchen (ein Beispiel unter: http://adomas.org/excc/ ).
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.