2009-05-04 35 views
18

Tôi phải sử dụng C cho một dự án và tôi đang nghĩ đến việc sử dụng longjmp/setjmp để xử lý lỗi vì tôi nghĩ sẽ dễ dàng xử lý lỗi ở một vị trí trung tâm hơn là mã trả lại. Tôi sẽ đánh giá cao nếu có một số khách hàng tiềm năng về cách thực hiện điều này.Một số cách "tốt" để sử dụng longjmp/setjmp để xử lý lỗi C là gì?

Tôi đặc biệt quan tâm đến việc dọn dẹp tài nguyên được thực hiện chính xác nếu xảy ra bất kỳ lỗi nào.

Ngoài ra, làm cách nào để xử lý các lỗi dẫn đến các chương trình đa luồng sử dụng chúng?

Thậm chí tốt hơn, có thư viện C nào đã tồn tại để xử lý lỗi/ngoại lệ không?

Trả lời

5

Tôi chỉ tìm thấy một sử dụng cho setjmp()/longjmp() và không liên quan đến xử lý lỗi.

Có thực sự là không cần phải sử dụng nó cho rằng vì nó luôn luôn có thể được refactored vào một cái gì đó dễ dàng hơn để làm theo. Việc sử dụng setjmp()/longjmp() rất giống với goto ở chỗ nó có thể dễ dàng bị lạm dụng. Bất cứ điều gì làm cho mã của bạn ít có thể đọc được là một ý tưởng tồi nói chung. Lưu ý rằng tôi không nói rằng họ vốn đã xấu, chỉ là họ có thể dẫn đến mã xấu dễ dàng hơn các lựa chọn thay thế.

FWIW, một nơi chúng vô giá là một dự án tôi đã làm trong những ngày đầu của ngành (khung thời gian MS-DOS 6). Tôi quản lý để đặt cùng một thư viện đa luồng hợp tác sử dụng Turbo C sử dụng các chức năng đó trong một hàm yield() để chuyển đổi các tác vụ.

Tôi khá chắc chắn tôi chưa chạm vào chúng (hoặc có nhu cầu) kể từ những ngày đó.

+1

+1 Tôi cũng chỉ sử dụng chúng một lần: Trong bản sao bảo vệ cho trò chơi DOS. Tôi sử dụng longjmp thay vì phân nhánh bình thường để gây nhầm lẫn cho bánh quy giòn. Điều đó phần nào làm việc vì mã được tạo ra trông giống như bất kỳ thứ gì ngoài một nhánh. :-) –

+0

Sự trùng hợp thú vị: Tôi đã xây dựng một ca xướng hợp tác ca. 1985 sử dụng setjmp()/longjmp() để chạy trên một máy trạm SGI dưới hương vị unix của chúng trong ngày. Làm việc như người ở. Kể từ khi nó được sử dụng cho hoạt hình, nó bao gồm một rendevous đồng bộ tất cả các chủ đề để gián đoạn theo chiều dọc của hệ thống video. Tôi đã không trực tiếp sử dụng chúng kể từ đó, tuy nhiên. – RBerteig

5

Symbian đã triển khai cơ chế Leave về mặt số longjmp() và điều này giúp bạn thực hiện tốt mọi việc bạn cần làm.

Symbian có 'ngăn xếp dọn dẹp' toàn cầu mà bạn nhấn và bật những thứ bạn muốn dọn dẹp nếu một bước nhảy xảy ra. Đây là sự thay thế thủ công đối với ngăn xếp tự động mà một trình biên dịch C++ thực hiện khi một ngoại lệ C++ được ném ra.

Symbian có 'bẫy khai thác' mà nó sẽ nhảy ra; chúng có thể được lồng nhau.

(Symbian gần đây đã thực hiện lại nó về ngoại lệ C++, nhưng giao diện vẫn không thay đổi).

Tất cả cùng nhau, tôi nghĩ rằng các trường hợp ngoại lệ C++ thích hợp ít bị lỗi mã hóa và nhanh hơn nhiều so với việc cuộn tương đương với C của bạn.

(trình biên dịch hiện đại C++ rất giỏi 'zero overhead' ngoại lệ khi họ không ném, ví dụ; longjmp() có để lưu trữ trạng thái của tất cả các thanh ghi và như vậy ngay cả khi nhảy được không muộn lấy, vì vậy có thể cơ bản không bao giờ nhanh như trường hợp ngoại lệ.)

Sử dụng C++ làm C tốt hơn, nơi bạn chỉ áp dụng ngoại lệ và RAII, là tuyến đường tốt nên sử dụng longjmp() để mô phỏng ngoại lệ hấp dẫn bạn.

+0

Vui lòng sử dụng tên chính xác: longjmp/setjmp, không phải 'longjump'. –

+0

cảm ơn thông tin. Tuy nhiên, câu hỏi là cụ thể để sử dụng C không C++ – dubnde

+0

@MeThinks, đó là tốt, lời khuyên của tôi là áp dụng cho C; Tôi vạch ra mô phỏng việc mở ngăn xếp (chẳng hạn như Ngăn xếp Dọn dẹp của Symbian) như cách bạn dọn dẹp tài nguyên mà bạn đã đặt ra trong câu hỏi của mình. – Will

0

Trường hợp ngoại lệ là một cơ chế chung tốt hơn nhiều, nhưng trong những ngày đen tối của quá khứ C, tôi đã viết trình giả lập bộ xử lý bao gồm một trình bao lệnh. Vỏ được sử dụng để setjmp/longjmp để xử lý gián đoạn (tức là, bộ vi xử lý đang chạy và người dùng nhấn break/ctrl-c, mã bẫy SIGINT và longjmps quay lại trình bao).

14

Nếu bạn đang lo lắng về dọn dẹp tài nguyên, bạn phải tự hỏi nghiêm túc dù longjmp() và setjmp() là một ý tưởng tốt.

Nếu bạn thiết kế hệ thống phân bổ tài nguyên để có thể làm sạch chính xác, thì OK - nhưng thiết kế đó có xu hướng phức tạp và thường không hoàn chỉnh nếu các thư viện chuẩn mà mã của bạn sử dụng phân bổ tài nguyên phải được phát hành. Nó đòi hỏi sự chăm sóc đặc biệt, và bởi vì nó không hoàn toàn đáng tin cậy, nó không thích hợp cho các hệ thống chạy dài có thể cần phải tồn tại nhiều lần sử dụng các lệnh setjmp()/longjmp() (chúng sẽ bị rò rỉ, mở rộng và cuối cùng) các vấn đề).

+1

+1, bởi vì không ai dường như đưa ra các câu trả lời hợp lý mà không chỉ trả lời một cách mù quáng câu hỏi – MatthewD

0

Tôi đã sử dụng setjmp/longjmp hợp lý gọn gàng, để thoát khỏi trong một cuộc gọi lại mà không phải thương lượng theo cách của mình thông qua các cấp thư viện khác nhau.

Trường hợp đó (nếu tôi nhớ chính xác) là nơi mã trong trình phân tích cú pháp được tạo ra yacc có thể phát hiện sự cố (không phải cú pháp) và muốn bỏ phân tích cú pháp nhưng báo cáo lỗi hữu ích hợp lý cho người gọi phía bên kia của tất cả mã được tạo ra yacc. Một ví dụ khác nằm trong một cuộc gọi lại được gọi từ trình phân tích cú pháp Expat. Trong mỗi trường hợp, có những cách khác để làm điều này, nhưng chúng có vẻ cồng kềnh và mơ hồ hơn là chỉ đơn giản là bailing ra theo cách này.

Như các câu trả lời khác đã chỉ ra, tuy nhiên, cần phải cẩn thận về việc dọn dẹp và rất thận trọng về việc đảm bảo rằng mã longjmp chỉ có thể gọi trong phạm vi của khu vực được bảo vệ động bởi setjmp.

Làm điều đó trong ngữ cảnh lập trình đa luồng? Tôi chắc chắn rằng đó không phải là không thể, nhưng Oooh: lấy gói thuốc aspirin gia đình của bạn ngay bây giờ. Có thể là khôn ngoan để giữ các cặp setjmp/longjmp càng gần nhau càng tốt. Miễn là một cặp setjmp/longjmp phù hợp nằm trong cùng một chuỗi, tôi hy vọng bạn sẽ OK, nhưng ... hãy cẩn thận ngoài đó.

Các vấn đề liên quan