Wpisałem to w Google, ale znalazłem tylko instrukcje w C ++,
jak to zrobić w C?
Wpisałem to w Google, ale znalazłem tylko instrukcje w C ++,
jak to zrobić w C?
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.
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 funkcja throw
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()
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
}
return 0;
}
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.
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żywanie last_error
zmiennej lub funkcji.Zobacz http://en.wikibooks.org/wiki/C_Programming/Error_handling .
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.
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>
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
w 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;
}
aby go skompilować
gcc -o bar.o -c bar.c && g++ a.cc bar.o && ./a.out
wynik
good 1976
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.
_ZTII
oznacza typeinfo for long
np echo '_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.
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.
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/ ).
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.