C nie obsługuje obsługi wyjątków. Aby zgłosić wyjątek w C, musisz użyć czegoś specyficznego dla platformy, na przykład strukturalnej obsługi wyjątków Win32 - ale aby udzielić pomocy, musimy znać platformę, na której Ci zależy.
Jerry Coffin
18
... i nie używaj strukturalnej obsługi wyjątków Win32.
Brian R. Bondy
4
Używanie setjmp () i longjmp () powinno teoretycznie działać, ale nie sądzę, aby było warte zachodu.
Jednak wyjątki są zdefiniowane w C ++ i innych językach. Obsługa wyjątków w C ++ jest określona w standardzie C ++ „S.15 Obsługa wyjątków”, w standardzie C nie ma odpowiedniej sekcji.
Więc w C jest gwarantowane, że nie będzie wyjątków, jak?
httpinterpret
62
@httpinterpret: w C jest „gwarantowane”, że nie ma wyjątków w ten sam sposób, w jaki „gwarantuje się”, że nie ma szablonów, ani odbić, ani jednorożców. Specyfikacja języka po prostu niczego takiego nie definiuje. Istnieje jednak setjmp / longjmp, którego można użyć do wyjścia z funkcji bez powrotu. Zatem programy mogą, jeśli chcą, budować własne mechanizmy podobne do wyjątków, lub implementacja w C może definiować rozszerzenia standardu.
Steve Jessop
2
Program ze mainw .cpliku może zawierać pewne C ++, a zatem wyjątki mogą być wyrzucane i złapany w programie, ale porcje kodu C pozostaną nieświadomi to wszystko dzieje się poza tym rzucaniu wyjątków i łapanie często opierają się na funkcji napisanych w C które znajdują się w bibliotekach C ++. C jest używane, ponieważ nie można ryzykować, że wywoływana funkcja throwmusi sama zgłosić wyjątek. Jednak może istnieć specyficzny dla kompilatora / biblioteki / celu sposób zgłaszania / przechwytywania wyjątków. Ale rzucenie instancji klasy będzie miało własne problemy.
nategoose
61
@Steve: Proszę, daj mi znać, jeśli znajdziesz język z jednorożcami, czekałem na coś takiego od lat.
Brian R. Bondy
5
@ BrianR.Bondy Oto język z jednorożcami (gwarantuję to tak samo jak w C)
Tofandel
38
W C możesz użyć kombinacji funkcji setjmp()i longjmp(), zdefiniowanych w setjmp.h. Przykład z Wikipedii
#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;}
Uwaga: właściwie radziłbym ci ich nie używać, ponieważ działają okropnie z C ++ (destruktory lokalnych obiektów nie zostałyby wywołane) i naprawdę trudno jest zrozumieć, co się dzieje. Zamiast tego zwróć jakiś błąd.
Widziałem, że setjump / longjump nie działa poprawnie w programach C ++, nawet jeśli żadne obiekty nie wymagały zniszczenia, gdy zostały użyte wyjątki. Rzadko używam ich w programach C.
nategoose
To było ciekawe podejście przy użyciu setjmp. on-time.com/ddj0011.htm Ale tak, w zasadzie musisz je sam wymyślić, jeśli chcesz wykonywać kod poza pasmem bez rozwijania stosu.
Dwayne Robinson
Nie jestem pewien, dlaczego zastrzeżenie dotyczące używania ich w C ++, gdy pytanie dotyczy C, a C ++ i tak ma wyjątki. W każdym razie ważne jest, aby OP wiedział, że aby uniemożliwić implementacji setjmp / longjmp odstrzelenie nogi, zawsze pamiętaj, że najpierw musisz odwiedzić program obsługi błędów (aby go skonfigurować) i ten moduł obsługi błędów musi wrócić dwa razy.
1
Nawiasem mówiąc, obsługa wyjątków była czymś, co naprawdę miałem nadzieję, że trafi do C11. Pomimo powszechnego przekonania, nie wymaga on OOP do prawidłowego działania, a C cierpi bez końca z powodu każdego wywołania funkcji wymagającego if(). Nie widzę w tym niebezpieczeństwa; czy może tu ktoś jeszcze?
@ user4229245 Mam (anegdotyczne) wrażenie, że wszystko, co „zrobiono dla ciebie”, jest trzymane poza specyfikacją języka c tak bardzo, jak to możliwe, szczególnie po to, aby c było odpowiednie dla programowania od podstaw i maszyn, gdzie nawet podstawowe status quo, takie jak ośmiobitowe bajty, nie są Nie uniwersalne, tylko moje myśli, nie jestem autorem specyfikacji c
ThorSummoner
21
Zwykły stary C tak naprawdę nie obsługuje wyjątków natywnie.
Możesz użyć alternatywnych strategii obsługi błędów, takich jak:
zwracanie kodu błędu
zwracanie FALSEi używanie last_errorzmiennej lub funkcji.
Również interfejs API systemu Windows ma tę samą metodę obsługi błędów. na przykład GetLastError()w Windows API.
BattleTested
20
W C nie ma wbudowanego mechanizmu wyjątków; musisz symulować wyjątki i ich semantykę. Zwykle osiąga się to, polegając na setjmpilongjmp .
W okolicy jest sporo bibliotek, a ja wdrażam kolejną. Nazywa się exceptions4c ; jest przenośny i bezpłatny. Możesz przyjrzeć się temu i porównać z innymi alternatywami, aby sprawdzić, która najbardziej Ci odpowiada.
Czytałem przykład kodu, zacząłem podobny projekt ze strukturą, ale używam uuid zamiast ciągu do identyfikacji każdego „wyjątku”. Twój projekt wydaje się bardzo obiecujący.
Czy wiesz (lub ktokolwiek inny) o porównaniu różnych pakietów wyjątków?
Marcel Waldvogel
11
C może zgłosić wyjątek C ++, są to i tak kody maszynowe. Na przykład w 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
Co to do cholery jest "_ZTIl" ??? Nie mogę nigdzie znaleźć żadnego odniesienia do niego i jest kompletną tajemnicą, w jaki sposób kod C mógłby mieć dostęp do std :: type_info. Proszę pomóż mi!
AreusAstarte
1
_ZTIIoznacza typeinfo for longnp echo '_ZTIl' | c++filt . Jest to schemat zniekształcenia g ++.
wcy
i na wszelki wypadek wywołaj symbol ac w bloku catch, aby uniknąć c ++ tak bardzo, jak to możliwe: P (PS dziękuję za udostępnienie doskonałego prawdziwego przykładu!)
ThorSummoner
8
To pytanie jest bardzo stare, ale po prostu się na nie natknąłem i pomyślałem, że podzielę się techniką: dzielenie przez zero lub odwoływanie się do pustego wskaźnika.
Pytanie brzmi po prostu „jak wyrzucić”, a nie jak wyłapać, czy nawet jak wyrzucić określony typ wyjątku. Wieki temu miałem sytuację, w której musieliśmy wyzwolić wyjątek z C, aby został przechwycony w C ++. W szczególności od czasu do czasu otrzymywaliśmy raporty o błędach „czystego wywołania funkcji wirtualnej” i musieliśmy przekonać funkcję _purecall środowiska wykonawczego języka C do rzucenia czegoś. Więc dodaliśmy naszą własną funkcję _purecall, która jest podzielona przez zero i bum, otrzymaliśmy wyjątek, który mogliśmy złapać w C ++, a nawet wykorzystać trochę stosu, aby zobaczyć, gdzie coś poszło nie tak.
Jak wspomniano w wielu wątkach, „standardowym” sposobem jest użycie setjmp / longjmp. Kolejne takie rozwiązanie zamieściłem na https://github.com/psevon/exceptions-and-raii-in-c
Jest to według mojej wiedzy jedyne rozwiązanie, które polega na automatycznym czyszczeniu przydzielonych zasobów. Implementuje unikalne i współdzielone inteligentne wskaźniki i umożliwia pośredniczącym funkcjom przepuszczanie wyjątków bez przechwytywania i nadal prawidłowo oczyszczane lokalnie przydzielone zasoby.
C nie obsługuje wyjątków. Możesz spróbować skompilować swój kod w C jako C ++ z Visual Studio lub G ++ i sprawdzić, czy skompiluje się tak, jak jest. Większość aplikacji C skompiluje się jako C ++ bez większych zmian, a następnie możesz użyć składni try ... catch.
Jeśli piszesz kod z wzorcem projektowym Happy path (np. Dla urządzenia osadzonego), możesz zasymulować przetwarzanie błędów wyjątków (aka deffering lub wreszcie emulacja) za pomocą operatora „goto”.
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;}
W rzeczywistości nie obsługuje on obsługi wyjątków, ale umożliwia obsługę błędu przy wyjściu funkcji.
PS Powinieneś uważać, aby używać goto tylko z tych samych lub więcej głębokich zakresów i nigdy nie przeskakiwać deklaracji zmiennych.
Odpowiedzi:
Nie ma wyjątków w C. W C błędy są zgłaszane przez zwróconą wartość funkcji, wartość wyjścia procesu, sygnały do procesu ( Sygnały Błędów Programu (GNU libc) ) lub przerwanie sprzętowe CPU (lub inne powiadomienie błąd z procesora, jeśli istnieje) ( Jak procesor obsługuje przypadek dzielenia przez zero ).
Jednak wyjątki są zdefiniowane w C ++ i innych językach. Obsługa wyjątków w C ++ jest określona w standardzie C ++ „S.15 Obsługa wyjątków”, w standardzie C nie ma odpowiedniej sekcji.
źródło
main
w.c
pliku może zawierać pewne C ++, a zatem wyjątki mogą być wyrzucane i złapany w programie, ale porcje kodu C pozostaną nieświadomi to wszystko dzieje się poza tym rzucaniu wyjątków i łapanie często opierają się na funkcji napisanych w C które znajdują się w bibliotekach C ++. C jest używane, ponieważ nie można ryzykować, że wywoływana funkcjathrow
musi sama zgłosić wyjątek. Jednak może istnieć specyficzny dla kompilatora / biblioteki / celu sposób zgłaszania / przechwytywania wyjątków. Ale rzucenie instancji klasy będzie miało własne problemy.W C możesz użyć kombinacji funkcji
setjmp()
ilongjmp()
, zdefiniowanych wsetjmp.h
. Przykład z WikipediiUwaga: właściwie radziłbym ci ich nie używać, ponieważ działają okropnie z C ++ (destruktory lokalnych obiektów nie zostałyby wywołane) i naprawdę trudno jest zrozumieć, co się dzieje. Zamiast tego zwróć jakiś błąd.
źródło
if()
. Nie widzę w tym niebezpieczeństwa; czy może tu ktoś jeszcze?Zwykły stary C tak naprawdę nie obsługuje wyjątków natywnie.
Możesz użyć alternatywnych strategii obsługi błędów, takich jak:
FALSE
i używanielast_error
zmiennej lub funkcji.Zobacz http://en.wikibooks.org/wiki/C_Programming/Error_handling .
źródło
GetLastError()
w Windows API.W C nie ma wbudowanego mechanizmu wyjątków; musisz symulować wyjątki i ich semantykę. Zwykle osiąga się to, polegając na
setjmp
ilongjmp
.W okolicy jest sporo bibliotek, a ja wdrażam kolejną. Nazywa się exceptions4c ; jest przenośny i bezpłatny. Możesz przyjrzeć się temu i porównać z innymi alternatywami, aby sprawdzić, która najbardziej Ci odpowiada.
źródło
C może zgłosić wyjątek C ++, są to i tak kody maszynowe. Na przykład w bar.c
w a.cc,
aby go skompilować
wynik
Więcej szczegółowych informacji można znaleźć w witrynie http://mentorembedded.github.io/cxx-abi/abi-eh.html
__cxa_throw
.Nie jestem pewien, czy jest przenośny, czy nie, i testuję go z 'gcc-4.8.2' w systemie Linux.
źródło
_ZTII
oznaczatypeinfo for long
npecho '_ZTIl' | c++filt
. Jest to schemat zniekształcenia g ++.To pytanie jest bardzo stare, ale po prostu się na nie natknąłem i pomyślałem, że podzielę się techniką: dzielenie przez zero lub odwoływanie się do pustego wskaźnika.
Pytanie brzmi po prostu „jak wyrzucić”, a nie jak wyłapać, czy nawet jak wyrzucić określony typ wyjątku. Wieki temu miałem sytuację, w której musieliśmy wyzwolić wyjątek z C, aby został przechwycony w C ++. W szczególności od czasu do czasu otrzymywaliśmy raporty o błędach „czystego wywołania funkcji wirtualnej” i musieliśmy przekonać funkcję _purecall środowiska wykonawczego języka C do rzucenia czegoś. Więc dodaliśmy naszą własną funkcję _purecall, która jest podzielona przez zero i bum, otrzymaliśmy wyjątek, który mogliśmy złapać w C ++, a nawet wykorzystać trochę stosu, aby zobaczyć, gdzie coś poszło nie tak.
źródło
int div_by_nil(int x) { return x/0; }
W Win z MSVC jest
__try ... __except ...
to naprawdę okropne i nie chcesz go używać, jeśli możesz tego uniknąć. Lepiej powiedzieć, że nie ma wyjątków.źródło
C nie ma wyjątków.
Istnieją różne hackerskie implementacje, które próbują to zrobić (jeden przykład na: http://adomas.org/excc/ ).
źródło
Jak wspomniano w wielu wątkach, „standardowym” sposobem jest użycie setjmp / longjmp. Kolejne takie rozwiązanie zamieściłem na https://github.com/psevon/exceptions-and-raii-in-c Jest to według mojej wiedzy jedyne rozwiązanie, które polega na automatycznym czyszczeniu przydzielonych zasobów. Implementuje unikalne i współdzielone inteligentne wskaźniki i umożliwia pośredniczącym funkcjom przepuszczanie wyjątków bez przechwytywania i nadal prawidłowo oczyszczane lokalnie przydzielone zasoby.
źródło
C nie obsługuje wyjątków. Możesz spróbować skompilować swój kod w C jako C ++ z Visual Studio lub G ++ i sprawdzić, czy skompiluje się tak, jak jest. Większość aplikacji C skompiluje się jako C ++ bez większych zmian, a następnie możesz użyć składni try ... catch.
źródło
Jeśli piszesz kod z wzorcem projektowym Happy path (np. Dla urządzenia osadzonego), możesz zasymulować przetwarzanie błędów wyjątków (aka deffering lub wreszcie emulacja) za pomocą operatora „goto”.
W rzeczywistości nie obsługuje on obsługi wyjątków, ale umożliwia obsługę błędu przy wyjściu funkcji.
PS Powinieneś uważać, aby używać goto tylko z tych samych lub więcej głębokich zakresów i nigdy nie przeskakiwać deklaracji zmiennych.
źródło