C tidak mendukung penanganan pengecualian. Untuk melempar pengecualian di C, Anda perlu menggunakan platform yang spesifik seperti penanganan pengecualian terstruktur Win32 - tetapi untuk memberikan bantuan apa pun dengan itu, kami perlu mengetahui platform yang Anda pedulikan.
Jerry Coffin
18
... dan jangan gunakan penanganan pengecualian terstruktur Win32.
Brian R. Bondy
4
Menggunakan setjmp () dan longjmp () seharusnya, secara teori, berhasil, tapi menurut saya itu tidak sepadan dengan masalahnya.
Pengecualian didefinisikan dalam C ++ dan bahasa lain. Penanganan pengecualian di C ++ ditentukan dalam standar C ++ "Penanganan pengecualian S.15", tidak ada bagian yang setara dalam standar C.
Jadi di C dijamin tidak akan ada pengecualian, bagaimana caranya?
httpinterpret
62
@httpinterpret: dalam C "dijamin" bahwa tidak ada pengecualian dengan cara yang sama seperti "dijamin" bahwa tidak ada template, atau refleksi, atau unicorn. Spesifikasi bahasa sama sekali tidak mendefinisikan hal seperti itu. Ada setjmp / longjmp, yang bisa digunakan untuk keluar dari fungsi tanpa kembali. Jadi program dapat membangun mekanisme seperti pengecualian mereka sendiri jika mereka mau, atau implementasi C dapat menentukan ekstensi ke standar.
Steve Jessop
2
Sebuah program dengan maindi .cfile yang dapat mencakup beberapa C ++, dan karena itu pengecualian bisa dilemparkan dan tertangkap dalam program ini, tetapi bagian-bagian kode C akan tetap tahu tentang semua ini terjadi kecuali bahwa pengecualian melempar dan menangkap sering mengandalkan fungsi ditulis dalam C yang berada di pustaka C ++. C digunakan karena Anda tidak dapat mengambil risiko fungsi yang dipanggil untuk melakukan throwpengecualian itu sendiri. Mungkin ada cara spesifik compiler / library / target untuk melempar / menangkap pengecualian. Tapi melempar instance kelas akan memiliki masalahnya sendiri.
nategoose
61
@Steve: Tolong beri tahu saya jika Anda menemukan bahasa dengan unicorn, saya telah menunggu hal seperti itu selama bertahun-tahun.
Brian R. Bondy
5
@ BrianR.Bondy Ini adalah bahasa dengan unicorn (saya jamin dengan cara yang sama seperti yang dijamin di C)
Tofandel
38
Di C Anda bisa menggunakan kombinasi dari setjmp()dan longjmp()fungsi, yang didefinisikan di setjmp.h. Contoh dari Wikipedia
#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;}
Catatan: Saya benar-benar menyarankan Anda untuk tidak menggunakannya karena mereka bekerja buruk dengan C ++ (penghancur objek lokal tidak akan dipanggil) dan sangat sulit untuk memahami apa yang sedang terjadi. Kembalikan beberapa jenis kesalahan sebagai gantinya.
Saya telah melihat setjump / longjump tidak berfungsi dengan benar di program C ++ bahkan ketika tidak ada objek yang perlu dimusnahkan ketika pengecualian digunakan. Saya jarang menggunakannya dalam program C.
nategoose
Ini adalah pendekatan yang menarik menggunakan setjmp. on-time.com/ddj0011.htm Tapi ya, pada dasarnya Anda harus menemukannya sendiri jika Anda ingin eksekusi kode out-of-band tanpa melepas tumpukan.
Dwayne Robinson
Saya tidak yakin mengapa peringatan tentang menggunakannya dalam C ++ ketika pertanyaannya adalah tentang C dan C ++ memiliki pengecualian. Bagaimanapun, penting bagi OP untuk mengetahui bahwa untuk menjaga implementasi setjmp / longjmp dari menembak kaki Anda, selalu ingat bahwa Anda harus terlebih dahulu mengunjungi penangan kesalahan (untuk menyiapkannya), dan penangan kesalahan itu perlu kembali dua kali.
1
Ngomong-ngomong, penanganan pengecualian adalah sesuatu yang benar-benar saya harapkan akan berakhir di C11. Terlepas dari kepercayaan umum, itu tidak memerlukan OOP untuk berfungsi dengan baik, dan C menderita tanpa henti oleh setiap pemanggilan fungsi yang membutuhkan if(). Saya tidak bisa melihat bahaya di dalamnya; bisakah orang lain disini?
@ user4229245 Saya berada di bawah kesan (anekdotal) apa pun yang "dilakukan untuk Anda" dijauhkan dari spesifikasi bahasa c sebanyak mungkin secara khusus untuk menjaga agar c tetap relevan untuk bare metal dan pemrograman mesin di mana bahkan fundamental status quo seperti delapan bit byte isn Tidak universal, hanya pemikiran saya, saya bukan penulis spesifikasi c
ThorSummoner
21
C lama biasa sebenarnya tidak mendukung pengecualian secara native.
Anda dapat menggunakan strategi penanganan kesalahan alternatif, seperti:
mengembalikan kode kesalahan
kembali FALSEdan menggunakan last_errorvariabel atau fungsi.
Juga api windows memiliki metode yang sama untuk menangani kesalahan. misalnya GetLastError()di windows API.
BattleTested
20
Ada tidak ada built-in mekanisme pengecualian dalam C; Anda perlu menyimulasikan pengecualian dan semantiknya. Ini biasanya dicapai dengan mengandalkan setjmpdan longjmp.
Ada cukup banyak perpustakaan di sekitar, dan saya sedang mengimplementasikan yang lain. Ini disebut exceptionions4c ; portabel dan gratis. Anda dapat melihatnya, dan membandingkannya dengan alternatif lain untuk melihat mana yang paling cocok untuk Anda.
Saya membacakan contoh kode, saya memulai proyek serupa dengan struktur, tetapi menggunakan uuid, bukan string untuk mengidentifikasi setiap "pengecualian". Proyek Anda tampaknya sangat menjanjikan.
Apakah Anda (atau orang lain) tahu tentang perbandingan antara paket pengecualian yang berbeda?
Marcel Waldvogel
11
C dapat menampilkan pengecualian C ++, mereka tetap kode mesin. Misalnya, di 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
Apa itu "_ZTIl" ??? Saya tidak dapat menemukan referensi untuk itu di mana pun dan itu adalah misteri lengkap bagaimana memungkinkan kode C memiliki akses ke std :: type_info. Tolong bantu aku!
AreusAstarte
1
_ZTIIartinya typeinfo for long, mis echo '_ZTIl' | c++filt . Ini adalah skema mangling g ++.
wcy
dan hanya untuk ukuran yang baik, pastikan untuk memanggil simbol ac di blok tangkapan untuk menghindari c ++ sebanyak mungkin: P (PS terima kasih telah membagikan contoh nyata yang sangat baik!)
ThorSummoner
8
Pertanyaan ini sangat tua, tetapi saya baru saja menemukan itu dan berpikir saya akan berbagi teknik: bagi dengan nol, atau dereferensi penunjuk nol.
Pertanyaannya hanyalah "bagaimana cara melempar", bukan bagaimana cara menangkap, atau bahkan bagaimana cara melempar jenis pengecualian tertentu. Saya memiliki situasi berabad-abad yang lalu di mana kami perlu memicu pengecualian dari C untuk ditangkap di C ++. Secara khusus, kami memiliki laporan sesekali tentang kesalahan "panggilan fungsi virtual murni", dan perlu meyakinkan fungsi _purecall runtime C untuk melempar sesuatu. Jadi kami menambahkan fungsi _purecall kami sendiri yang dibagi dengan nol, dan boom, kami mendapat pengecualian yang dapat kami tangkap di C ++, dan bahkan menggunakan beberapa stack fun untuk melihat di mana ada yang salah.
@AreusAstarte untuk berjaga-jaga jika seseorang benar-benar perlu diperlihatkan pembagian C oleh nol:int div_by_nil(int x) { return x/0; }
7
Tentang Win with MSVC ada __try ... __except ...tetapi itu benar-benar mengerikan dan Anda tidak ingin menggunakannya jika Anda mungkin dapat menghindarinya. Lebih baik mengatakan bahwa tidak ada pengecualian.
Seperti disebutkan di banyak utas, cara "standar" untuk melakukan ini adalah menggunakan setjmp / longjmp. Saya memposting solusi lain seperti itu ke https://github.com/psevon/exceptions-and-raii-in-c. Sepengetahuan saya,
ini adalah satu-satunya solusi yang mengandalkan pembersihan otomatis sumber daya yang dialokasikan. Ini mengimplementasikan smartpointers yang unik dan bersama, dan memungkinkan fungsi perantara untuk membiarkan pengecualian lewat tanpa menangkap dan masih memiliki sumber daya yang dialokasikan secara lokal dibersihkan dengan benar.
C tidak mendukung pengecualian. Anda dapat mencoba mengompilasi kode C Anda sebagai C ++ dengan Visual Studio atau G ++ dan melihat apakah itu akan dikompilasi sebagaimana adanya. Sebagian besar aplikasi C akan dikompilasi sebagai C ++ tanpa perubahan besar, dan Anda kemudian dapat menggunakan sintaks try ... catch.
Jika Anda menulis kode dengan pola desain Happy path (yaitu untuk perangkat tertanam) Anda dapat mensimulasikan pemrosesan kesalahan pengecualian (alias menunda atau akhirnya emulasi) dengan operator "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;}
Ini tidak benar-benar pengecualian penangan tetapi itu membawa Anda cara untuk menangani kesalahan saat keluar dari fucntion.
PS Anda harus berhati-hati menggunakan goto hanya dari cakupan yang sama atau lebih dalam dan tidak pernah melompati deklarasi variabel.
Jawaban:
Tidak ada pengecualian di C. Dalam C kesalahan diberitahukan oleh nilai yang dikembalikan dari fungsi, nilai keluar dari proses, sinyal ke proses ( Program Error Signals (GNU libc) ) atau gangguan perangkat keras CPU (atau pemberitahuan lainnya kesalahan bentuk CPU jika ada) ( Bagaimana prosesor menangani kasus pembagian dengan nol ).
Pengecualian didefinisikan dalam C ++ dan bahasa lain. Penanganan pengecualian di C ++ ditentukan dalam standar C ++ "Penanganan pengecualian S.15", tidak ada bagian yang setara dalam standar C.
sumber
main
di.c
file yang dapat mencakup beberapa C ++, dan karena itu pengecualian bisa dilemparkan dan tertangkap dalam program ini, tetapi bagian-bagian kode C akan tetap tahu tentang semua ini terjadi kecuali bahwa pengecualian melempar dan menangkap sering mengandalkan fungsi ditulis dalam C yang berada di pustaka C ++. C digunakan karena Anda tidak dapat mengambil risiko fungsi yang dipanggil untuk melakukanthrow
pengecualian itu sendiri. Mungkin ada cara spesifik compiler / library / target untuk melempar / menangkap pengecualian. Tapi melempar instance kelas akan memiliki masalahnya sendiri.Di C Anda bisa menggunakan kombinasi dari
setjmp()
danlongjmp()
fungsi, yang didefinisikan disetjmp.h
. Contoh dari WikipediaCatatan: Saya benar-benar menyarankan Anda untuk tidak menggunakannya karena mereka bekerja buruk dengan C ++ (penghancur objek lokal tidak akan dipanggil) dan sangat sulit untuk memahami apa yang sedang terjadi. Kembalikan beberapa jenis kesalahan sebagai gantinya.
sumber
if()
. Saya tidak bisa melihat bahaya di dalamnya; bisakah orang lain disini?C lama biasa sebenarnya tidak mendukung pengecualian secara native.
Anda dapat menggunakan strategi penanganan kesalahan alternatif, seperti:
FALSE
dan menggunakanlast_error
variabel atau fungsi.Lihat http://en.wikibooks.org/wiki/C_Programming/Error_handling .
sumber
GetLastError()
di windows API.Ada tidak ada built-in mekanisme pengecualian dalam C; Anda perlu menyimulasikan pengecualian dan semantiknya. Ini biasanya dicapai dengan mengandalkan
setjmp
danlongjmp
.Ada cukup banyak perpustakaan di sekitar, dan saya sedang mengimplementasikan yang lain. Ini disebut exceptionions4c ; portabel dan gratis. Anda dapat melihatnya, dan membandingkannya dengan alternatif lain untuk melihat mana yang paling cocok untuk Anda.
sumber
C dapat menampilkan pengecualian C ++, mereka tetap kode mesin. Misalnya, di bar.c
di a.cc,
untuk menyusunnya
keluaran
http://mentorembedded.github.io/cxx-abi/abi-eh.html memiliki info lebih detail tentang
__cxa_throw
.Saya tidak yakin apakah ini portabel atau tidak, dan saya mengujinya dengan 'gcc-4.8.2' di Linux.
sumber
_ZTII
artinyatypeinfo for long
, misecho '_ZTIl' | c++filt
. Ini adalah skema mangling g ++.Pertanyaan ini sangat tua, tetapi saya baru saja menemukan itu dan berpikir saya akan berbagi teknik: bagi dengan nol, atau dereferensi penunjuk nol.
Pertanyaannya hanyalah "bagaimana cara melempar", bukan bagaimana cara menangkap, atau bahkan bagaimana cara melempar jenis pengecualian tertentu. Saya memiliki situasi berabad-abad yang lalu di mana kami perlu memicu pengecualian dari C untuk ditangkap di C ++. Secara khusus, kami memiliki laporan sesekali tentang kesalahan "panggilan fungsi virtual murni", dan perlu meyakinkan fungsi _purecall runtime C untuk melempar sesuatu. Jadi kami menambahkan fungsi _purecall kami sendiri yang dibagi dengan nol, dan boom, kami mendapat pengecualian yang dapat kami tangkap di C ++, dan bahkan menggunakan beberapa stack fun untuk melihat di mana ada yang salah.
sumber
int div_by_nil(int x) { return x/0; }
Tentang Win with MSVC ada
__try ... __except ...
tetapi itu benar-benar mengerikan dan Anda tidak ingin menggunakannya jika Anda mungkin dapat menghindarinya. Lebih baik mengatakan bahwa tidak ada pengecualian.sumber
C tidak memiliki pengecualian.
Ada berbagai implementasi hacky yang mencoba melakukannya (salah satu contohnya di: http://adomas.org/excc/ ).
sumber
Seperti disebutkan di banyak utas, cara "standar" untuk melakukan ini adalah menggunakan setjmp / longjmp. Saya memposting solusi lain seperti itu ke https://github.com/psevon/exceptions-and-raii-in-c. Sepengetahuan saya, ini adalah satu-satunya solusi yang mengandalkan pembersihan otomatis sumber daya yang dialokasikan. Ini mengimplementasikan smartpointers yang unik dan bersama, dan memungkinkan fungsi perantara untuk membiarkan pengecualian lewat tanpa menangkap dan masih memiliki sumber daya yang dialokasikan secara lokal dibersihkan dengan benar.
sumber
C tidak mendukung pengecualian. Anda dapat mencoba mengompilasi kode C Anda sebagai C ++ dengan Visual Studio atau G ++ dan melihat apakah itu akan dikompilasi sebagaimana adanya. Sebagian besar aplikasi C akan dikompilasi sebagai C ++ tanpa perubahan besar, dan Anda kemudian dapat menggunakan sintaks try ... catch.
sumber
Jika Anda menulis kode dengan pola desain Happy path (yaitu untuk perangkat tertanam) Anda dapat mensimulasikan pemrosesan kesalahan pengecualian (alias menunda atau akhirnya emulasi) dengan operator "goto".
Ini tidak benar-benar pengecualian penangan tetapi itu membawa Anda cara untuk menangani kesalahan saat keluar dari fucntion.
PS Anda harus berhati-hati menggunakan goto hanya dari cakupan yang sama atau lebih dalam dan tidak pernah melompati deklarasi variabel.
sumber