Как бросить исключение в C? - PullRequest
76 голосов
/ 23 мая 2010

Я набрал это в Google, но нашел только Howtos в C ++,

как это сделать в C?

Ответы [ 10 ]

62 голосов
/ 23 мая 2010

Нет исключений в C. В C ошибки сообщаются по возвращенному значению функции, выходному значению процесса, сигналам процесса ( Program Error Signals (GNU libc) ) или аппаратное прерывание ЦП (или другая ошибка уведомления ЦПУ, если таковая имеется) ( Как процессор обрабатывает случай деления на ноль ).

Исключения определены в C ++ и других языках. Обработка исключений в C ++ определена в стандарте C ++ «Обработка исключений S.15», эквивалентного раздела в стандарте C нет.

29 голосов
/ 23 мая 2010

В 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 ++ (деструкторыместные объекты не будут вызываться) и действительно трудно понять, что происходит.Вместо этого верните какую-нибудь ошибку.

18 голосов
/ 23 мая 2010

Обычный старый C фактически не поддерживает исключения.

Вы можете использовать альтернативные стратегии обработки ошибок, такие как:

  • , возвращая код ошибки
  • возвращая FALSE и используя last_error переменную или функцию.

См. http://en.wikibooks.org/wiki/C_Programming/Error_handling.

16 голосов
/ 28 апреля 2011

Нет встроенного механизма исключений в C; вам нужно моделировать исключения и их семантику. Обычно это достигается за счет использования setjmp и longjmp.

Вокруг немало библиотек, и я внедряю еще одну. Это называется exceptions4c ; это портативный и бесплатный. Вы можете взглянуть на это и сравнить его с другими альтернативами , чтобы увидеть, что вам больше подходит.

9 голосов
/ 30 июня 2014

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

в .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.

6 голосов
/ 28 марта 2014

Этот вопрос очень старый, но я наткнулся на него и подумал, что поделюсь методом: делить на ноль или разыменовывать нулевой указатель.

Вопрос просто в том, «как бросить», а не в том, как поймать или даже как генерировать исключение определенного типа. У меня была ситуация давным-давно, когда нам нужно было вызвать исключение из C, чтобы быть пойманным в C ++. В частности, мы периодически получали сообщения об ошибках «чисто виртуального вызова функции», и нам нужно было убедить функцию _purecall среды выполнения C выдать что-то. Поэтому мы добавили нашу собственную функцию _purecall, которая делится на ноль, и boom, мы получили исключение, которое мы могли бы отловить на C ++ и даже использовать некоторое удовольствие от стека, чтобы увидеть, где что-то пошло не так.

6 голосов
/ 23 мая 2010

В Win с MSVC есть __try ... __except ..., но это действительно ужасно, и вы не хотите использовать его, если можете избежать этого. Лучше сказать, что нет никаких исключений.

6 голосов
/ 23 мая 2010

C не имеет исключений.

Существуют различные хакерские реализации, которые пытаются это сделать (один пример: http://adomas.org/excc/).

3 голосов
/ 08 апреля 2014

Как упоминалось во многих потоках, "стандартный" способ сделать это - использовать setjmp / longjmp. Я отправил еще одно такое решение для https://github.com/psevon/exceptions-and-raii-in-c Насколько мне известно, это единственное решение, основанное на автоматической очистке выделенных ресурсов. Он реализует уникальные и общие интеллектуальные указатели и позволяет промежуточным функциям пропускать исключения без перехвата и при этом правильно очищать свои локально распределенные ресурсы.

2 голосов
/ 23 мая 2010

C не поддерживает исключения. Вы можете попробовать скомпилировать ваш код C как C ++ с помощью Visual Studio или G ++ и посмотреть, будет ли он компилироваться как есть. Большинство приложений C будут компилироваться как C ++ без существенных изменений, и тогда вы можете использовать синтаксис try ... catch.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...