Я набрал это в Google, но нашел только в C ++,
как это сделать на C?
Я набрал это в Google, но нашел только в C ++,
как это сделать на C?
Ответы:
В C нет исключений. В C об ошибках сообщают возвращаемое значение функции, значение выхода процесса, сигналы процессу ( сигналы программных ошибок (GNU libc) ) или аппаратное прерывание ЦП (или другое уведомление. ошибка ЦП, если есть) ( Как процессор обрабатывает случай деления на ноль ).
Однако исключения определены в C ++ и других языках. Обработка исключений в C ++ описана в стандарте C ++ «S.15 Exception processing», в стандарте C нет эквивалентного раздела.
main
в .c
файле, может включать в себя некоторый C ++, и, следовательно, исключения могут быть выброшены и перехвачены в программе, но части кода C будут оставаться в неведении обо всем этом, за исключением того, что генерирование и перехват исключений часто полагаются на функции, написанные на C которые находятся в библиотеках C ++. C используется, потому что вы не можете рисковать, чтобы вызываемая функция throw
сама генерировала исключение. Однако может существовать специфический для компилятора / библиотеки / целевой способ генерирования / перехвата исключений. Но бросок экземпляра класса будет иметь свои проблемы.
В C вы можете использовать комбинацию setjmp()
и longjmp()
функций, определенных в setjmp.h
. Пример из Википедии
#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;
}
Примечание: на самом деле я бы посоветовал вам не использовать их, поскольку они ужасно работают с C ++ (деструкторы локальных объектов не вызываются), и очень сложно понять, что происходит. Вместо этого верните какую-то ошибку.
if()
. Я не вижу в этом опасности; может кто-нибудь еще здесь?
Обычный старый C на самом деле изначально не поддерживает исключения.
Вы можете использовать альтернативные стратегии обработки ошибок, например:
FALSE
и использование last_error
переменной или функции.См. Http://en.wikibooks.org/wiki/C_Programming/Error_handling .
GetLastError()
в Windows API.
В C нет встроенного механизма исключения; вам необходимо моделировать исключения и их семантику. Обычно это достигается за счет использования setjmp
и longjmp
.
Вокруг довольно много библиотек, и я реализую еще одну. Это называется exceptions4c ; это портативный и бесплатный. Вы можете взглянуть на него и сравнить с другими альтернативами, чтобы увидеть, что вам больше всего подходит.
C может генерировать исключение C ++, в любом случае это машинные коды. Например, в 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
в 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;
}
скомпилировать это
gcc -o bar.o -c bar.c && g++ a.cc bar.o && ./a.out
вывод
good 1976
http://mentorembedded.github.io/cxx-abi/abi-eh.html содержит более подробную информацию о __cxa_throw
.
Я не уверен, переносится он или нет, и я тестировал его с помощью gcc-4.8.2 в Linux.
_ZTII
означает typeinfo for long
, например echo '_ZTIl' | c++filt
. Это схема искажения g ++.
Этот вопрос очень старый, но я только что наткнулся на него и подумал, что поделюсь методом: деление на ноль или разыменование нулевого указателя.
Вопрос просто в том, «как выбросить», а не в том, как отловить или даже как выбросить определенный тип исключения. У меня была ситуация давным-давно, когда нам нужно было вызвать исключение из C, чтобы его перехватили в C ++. В частности, у нас были случайные сообщения об ошибках «вызова чисто виртуальной функции», и нам нужно было убедить функцию _purecall среды выполнения C что-то выбросить. Итак, мы добавили нашу собственную функцию _purecall, которая делится на ноль, и бум, мы получили исключение, которое мы могли поймать на C ++ и даже использовать некоторую забаву стека, чтобы увидеть, где что-то пошло не так.
В Win с MSVC есть, __try ... __except ...
но это действительно ужасно, и вы не хотите использовать его, если можете этого избежать. Лучше сказать, что здесь нет исключений.
В C нет исключений.
Существуют различные хитрые реализации, которые пытаются это сделать (один пример на: http://adomas.org/excc/ ).
Как упоминалось во многих потоках, «стандартный» способ сделать это - использовать setjmp / longjmp. Я разместил еще одно такое решение на https://github.com/psevon/exceptions-and-raii-in-c. Насколько мне известно, это единственное решение, которое полагается на автоматическую очистку выделенных ресурсов. Он реализует уникальные и общие смарт-указатели и позволяет промежуточным функциям пропускать исключения без их перехвата и при этом правильно очищать свои локально выделенные ресурсы.
C не поддерживает исключения. Вы можете попробовать скомпилировать свой код C как C ++ с помощью Visual Studio или G ++ и посмотреть, будет ли он компилироваться как есть. Большинство приложений C компилируются как C ++ без значительных изменений, и затем вы можете использовать синтаксис try ... catch.
Если вы пишете код с шаблоном проектирования «Счастливый путь» (например, для встроенного устройства), вы можете имитировать обработку ошибок исключения (также известную как дефферинг или, наконец, эмуляция) с помощью оператора «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;
}
На самом деле это не обработчик исключений, но он поможет вам обработать ошибку при выходе из функции.
PS Вы должны быть осторожны, используя goto только из той же или более глубокой области видимости и никогда не переходите через объявление переменных.