Я набрав це в google, але знайшов лише інструкції на C ++,
як це зробити на C?
Я набрав це в google, але знайшов лише інструкції на C ++,
як це зробити на C?
Відповіді:
У C. немає винятків. У C помилки повідомляються повернутим значенням функції, значенням виходу процесу, сигналами до процесу ( сигнали про помилки програми (GNU libc) ) або апаратним перериванням процесора (або іншим повідомленням помилка у формі центрального процесора (якщо є) ( Як процесор обробляє випадок ділення на нуль ).
Винятки визначені в C ++ та інших мовах. Обробка винятків у C ++ вказана у стандарті C ++ "S.15 Обробка винятків", у стандарті 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()
в API Windows.
У 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 ++.
Це запитання дуже старе, але я просто наткнувся на нього і подумав, що поділюсь технікою: ділити на нуль або відмінювати нульовий покажчик.
Питання просто в тому, "як кинути", а не в тому, як зловити, або навіть у тому, як кинути певний тип винятку. У мене була ситуація багато років тому, коли нам потрібно було викликати виняток із С, щоб потрапити в С ++. Зокрема, ми випадково повідомляли про помилки "чистого виклику віртуальної функції", і нам потрібно було переконати функцію _purecall середовища виконання C щось кинути. Отже, ми додали власну функцію _purecall, поділену на нуль, і бум, отримали виняток, який ми могли вловити на C ++, і навіть використати деякі розваги для стека, щоб побачити, де щось пішло не так.
У Win with 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;
}
Насправді це не обробник винятків, але він допоможе вам обробити помилку при виході з fucntion.
PS Ви повинні бути обережними, використовуючи goto лише з того самого або більше глибоких областей застосування, і ніколи не переходити до декларації змінних.