Tôi đã nhập cái này vào google nhưng chỉ tìm thấy howtos trong C ++,
làm thế nào để làm điều đó trong C?
Tôi đã nhập cái này vào google nhưng chỉ tìm thấy howtos trong C ++,
làm thế nào để làm điều đó trong C?
Câu trả lời:
Không có ngoại lệ trong C. Trong C, các lỗi được thông báo bằng giá trị trả về của hàm, giá trị thoát của quá trình, các tín hiệu cho quá trình ( Tín hiệu lỗi chương trình (GNU libc) ) hoặc ngắt phần cứng CPU (hoặc thông báo khác lỗi hình thành CPU nếu có) ( Cách bộ xử lý xử lý trường hợp chia cho 0 ).
Tuy nhiên, các ngoại lệ được định nghĩa trong C ++ và các ngôn ngữ khác. Xử lý ngoại lệ trong C ++ được quy định trong tiêu chuẩn C ++ "S.15 Xử lý ngoại lệ", không có phần tương đương trong tiêu chuẩn C.
main
trong .c
tệp có thể bao gồm một số C ++, và do đó các ngoại lệ có thể được ném và bắt trong chương trình, nhưng các phần mã C sẽ không biết về tất cả những điều này đang diễn ra ngoại trừ việc ném và bắt ngoại lệ thường dựa vào các hàm được viết bằng C. nằm trong các thư viện C ++. C được sử dụng vì bạn không thể mạo hiểm với hàm được gọi là throw
cần thực hiện chính nó. Tuy nhiên, có thể có một trình biên dịch / thư viện / đích cụ thể để ném / bắt các ngoại lệ. Nhưng ném một cá thể lớp sẽ có vấn đề riêng.
Trong C, bạn có thể sử dụng kết hợp các hàm setjmp()
và longjmp()
, được định nghĩa trong setjmp.h
. Ví dụ từ 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
}
return 0;
}
Lưu ý: Tôi thực sự khuyên bạn không nên sử dụng chúng vì chúng hoạt động tồi tệ với C ++ (hàm hủy của các đối tượng cục bộ sẽ không được gọi) và thực sự khó hiểu chuyện gì đang xảy ra. Thay vào đó, hãy trả lại một số loại lỗi.
if()
. Tôi không thể nhìn thấy một mối nguy hiểm trong đó; có ai khác ở đây được không?
Nguyên bản C cũ không hỗ trợ các ngoại lệ.
Bạn có thể sử dụng các chiến lược xử lý lỗi thay thế, chẳng hạn như:
FALSE
và sử dụng một last_error
biến hoặc hàm.Xem http://en.wikibooks.org/wiki/C_Programming/Error_handling .
GetLastError()
trong API windows.
Không có built-in cơ chế ngoại lệ trong C; bạn cần mô phỏng các ngoại lệ và ngữ nghĩa của chúng. Điều này thường đạt được bằng cách dựa vào setjmp
và longjmp
.
Có khá nhiều thư viện xung quanh và tôi đang triển khai một thư viện khác. Nó được gọi là exceptions4c ; nó di động và miễn phí. Bạn có thể xem xét nó và so sánh nó với các lựa chọn thay thế khác để xem cái nào phù hợp với bạn nhất.
C có thể ném ngoại lệ C ++, dù sao chúng cũng là mã máy. Ví dụ: trong 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
trong 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;
}
biên dịch nó
gcc -o bar.o -c bar.c && g++ a.cc bar.o && ./a.out
đầu ra
good 1976
http://mentorembedded.github.io/cxx-abi/abi-eh.html có thêm thông tin chi tiết về __cxa_throw
.
Tôi không chắc liệu nó có phải là portable hay không và tôi đã kiểm tra nó với 'gcc-4.8.2' trên Linux.
_ZTII
nghĩa là typeinfo for long
, ví dụ echo '_ZTIl' | c++filt
. Đó là lược đồ mangling g ++.
Câu hỏi này rất cũ, nhưng tôi chỉ tình cờ gặp nó và nghĩ rằng tôi muốn chia sẻ một kỹ thuật: chia cho không, hoặc bỏ tham chiếu một con trỏ rỗng.
Câu hỏi chỉ đơn giản là "làm thế nào để ném", không phải làm thế nào để bắt, hoặc thậm chí làm thế nào để ném một loại ngoại lệ cụ thể. Tôi đã gặp một tình huống từ rất lâu trước đây khi chúng tôi cần kích hoạt một ngoại lệ từ C để được bắt trong C ++. Cụ thể, chúng tôi thỉnh thoảng có báo cáo về lỗi "lệnh gọi hàm ảo thuần túy" và cần phải thuyết phục hàm _purecall của thời gian chạy C ném thứ gì đó. Vì vậy, chúng tôi đã thêm hàm _purecall của riêng mình chia cho 0 và boom, chúng tôi có một ngoại lệ mà chúng tôi có thể bắt gặp trên C ++ và thậm chí sử dụng một số trò chơi thú vị để xem mọi thứ đã sai ở đâu.
Trên Win với MSVC có __try ... __except ...
nhưng nó thực sự khủng khiếp và bạn không muốn sử dụng nó nếu có thể tránh được. Tốt hơn để nói rằng không có ngoại lệ.
C không có ngoại lệ.
Có nhiều cách triển khai hacky khác nhau cố gắng làm điều đó (một ví dụ tại: http://adomas.org/excc/ ).
Như đã đề cập trong nhiều chủ đề, cách "tiêu chuẩn" để thực hiện việc này là sử dụng setjmp / longjmp. Tôi đã đăng thêm một giải pháp khác như vậy lên https://github.com/psevon/exceptions-and-raii-in-c Đây là giải pháp duy nhất dựa vào việc tự động dọn dẹp tài nguyên được phân bổ. Nó triển khai các điểm thông minh duy nhất và được chia sẻ, đồng thời cho phép các chức năng trung gian cho phép các ngoại lệ đi qua mà không cần bắt và vẫn có các tài nguyên được phân bổ cục bộ của chúng được dọn dẹp đúng cách.
C không hỗ trợ các trường hợp ngoại lệ. Bạn có thể thử biên dịch mã C của mình dưới dạng C ++ bằng Visual Studio hoặc G ++ và xem liệu nó có biên dịch nguyên trạng hay không. Hầu hết các ứng dụng C sẽ biên dịch dưới dạng C ++ mà không có thay đổi lớn và sau đó bạn có thể sử dụng cú pháp try ... catch.
Nếu bạn viết mã với mẫu thiết kế đường dẫn Happy (tức là cho thiết bị nhúng), bạn có thể mô phỏng xử lý lỗi ngoại lệ (còn gọi là deffering hoặc cuối cùng là mô phỏng) với toán tử "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;
}
Nó không thực sự có trình xử lý ngoại lệ nhưng nó sẽ giúp bạn có một cách để xử lý lỗi khi thoát khỏi fucntion.
PS Bạn nên cẩn thận chỉ sử dụng goto từ các phạm vi tương tự hoặc nhiều hơn và không bao giờ nhảy khai báo biến.