2009-10-19 40 views
7

Trong một số dự án tôi đã thực hiện trong C, tôi đã thích sử dụng các macro sau đó làm việc tương tự như Perl của cảnh báo và chết chương trình con:Có tương đương C cho mô-đun Cá chép của Perl không?

#include <stdio.h> 
#include <stdlib.h> 

#define warn(...) \ 
    fprintf(stderr, __VA_ARGS__); \ 
    fprintf(stderr, " at %s line %d\n", __FILE__, __LINE__) 

#define die(...) \ 
    warn(__VA_ARGS__); \ 
    exit(0xFF) 

Liệu bất cứ điều gì tồn tại như cá chép Perl, tiếng kêu, túc túc, và thú nhận chương trình con từ Carp? Tôi muốn có một cái gì đó để báo cáo lỗi từ quan điểm của người dùng.

Nếu không, tôi biết có hàm backtrace() và backtrace_symbols() trong glibc cùng với tùy chọn gccnamric gcc có thể cung cấp cho tôi một backtrace tên hàm và địa chỉ mã. Nhưng tôi muốn một cái gì đó tốt hơn một chút; với quyền truy cập vào tên tệp, dòng và chức năng trong ngăn xếp cuộc gọi như trình con người gọi của Perl. với điều đó tôi có thể viết libcarp của riêng tôi để sử dụng trong các chương trình c của tôi.

EDIT: 2009-10-19

Tôi đang nghĩ đến việc tạo một cái gì đó mà sử dụng gdb khi sẵn trên basename (argv [0]), sau đó xử lý các vết đống để sản xuất các loại khác nhau của thông điệp tôi muốn . Nó sẽ có thể xác định nếu im không trong một thực thi debuggable, hoặc một hệ thống mà không gdb, trong trường hợp đó, cá chép và cluck sẽ trở thành cảnh báo và craok và thú nhận sẽ trở thành chết.

Tôi chưa bao giờ sử dụng gdb như thế này trước đây (Ive chỉ chạy nó với chương trình của tôi lúc đầu, không phải trong khi nó đang chạy). Nhưng tôi tìm thấy một vài hàm trong glib (g_on_error_stack_trace và stack_trace) trông rất gần với những gì tôi muốn làm: Nó dồn một quá trình gdb với tên đối số basename (argv [0]) và id tiến trình, sau đó ghi vào stdin của nó (đã được chuyển hướng đến một đường ống) lệnh "backtrace" theo sau là "quit". Sau đó nó đọc từ kết quả của nó và phân tích nó theo cách nó thích. Đây gần như chính xác những gì tôi cần làm.

+11

Đối với những người không quen thuộc với Perl, cá chép và croak làm những gì các mẫu cảnh báo và chết macro làm, chỉ với tập tin và dòng từ người gọi của phụ hiện tại. cluck và thú nhận làm như vậy, chỉ với một dấu vết stack hoàn chỉnh. (một số chi tiết được đơn giản hóa) – ysth

+4

Tài liệu tại: http://perldoc.perl.org/Carp.html – Ether

+4

Đối với các macro đa tuyên bố thực sự, chúng tôi khuyên bạn nên bọc chúng vào {...} trong khi (0), để thực hiện sử dụng như một tuyên bố làm việc như mong đợi. – unwind

Trả lời

1

Vâng, tôi chưa bao giờ cố gắng hiển thị ngăn xếp cuộc gọi, nhưng đối với các chương trình của tôi, tôi đã sử dụng để làm như sau.

Trước tiên, tôi xác định hàm thực hiện ghi nhật ký thực. Đây là chỉ là một ví dụ; xin lưu ý rằng chức năng này rất không an toàn (bộ đệm tràn ngập bất kỳ ai?)

void strLog(char *file, char *function, int line, char *fmt, ...) 
{ 
    char buf[1024]; 
    va_list args; 

    va_start(args, fmt); 
    vsprintf(buf, fmt, args); 
    va_end(args); 

    fprintf(stderr, "%s:%s:%d:%s\n", file, function, line, buf); 
} 

Tuy nhiên, điều này không thực tế lắm. Thực tế là sử dụng macro để gọi hàm này.

#define die(...) \ 
     strLog(__FILE__, __PRETTY_FUNCTION__, \ 
     __LINE__, __VA_ARGS__) 

Sau đó, bạn có thể gọi giống như printf().

if (answer == 42) die("Oh, %d of course.", answer); 

và bạn sẽ nhận được một cái gì đó như thế này:

main.c:10:somefunc: Oh, 42 of course. 

Vâng, không có vết lùi nhưng một cái gì đó một cái gì đó của.

+0

Dường như Jake đã có được điều đó. –

+2

Sử dụng vsnprintf() để ngăn chặn tràn bộ đệm. Hoặc sử dụng hai lệnh gọi hàm fprintf() - một cho thông tin tệp/chức năng/dòng và thông tin còn lại dưới dạng vfprintf() để xử lý định dạng do người dùng cung cấp. Mã của mọi người dường như bị quên để in tên chương trình - argv [0]; mà đòi hỏi một số kỷ luật thiết lập, mặc dù. –

+1

Nếu bạn muốn ngăn chặn tràn bộ đệm, cách dễ nhất để làm điều đó là gọi 'vasprintf' thay vì' vsnprintf'. –

1

Nhưng tôi muốn một cái gì đó tốt hơn một chút với quyền truy cập vào tên tệp, dòng và chức năng trong ngăn xếp cuộc gọi như trình con người gọi của Perl.

Vấn đề là điều này đòi hỏi sự giúp đỡ của lập trình viên để quyết định ranh giới xuất hiện giữa mã thư viện của bạn và chương trình con 'người gọi'. Perl sử dụng một số phép thuật (aka heuristics) để làm điều đó; có lẽ bạn có thể làm tương tự với các chức năng backtrace. Nhưng nó không phải là tầm thường, nói chung.

+1

Phép thuật được gọi ở đây là chức năng gọi được cung cấp là một trong các chức năng được tích hợp sẵn. Không có hàm chuẩn nào trong định nghĩa ngôn ngữ C cung cấp khả năng tương đương. –

+0

Tôi có nghĩa là "Phép thuật được nhắc đến ở đây là chức năng người gọi được cung cấp như một trong những hàm được xây dựng trong hàm. Không có hàm chuẩn nào trong định nghĩa ngôn ngữ C cung cấp khả năng tương đương." –

+1

@ David: Tôi biết những gì bạn đang nhận được, và nó là khó giải thích những gì sẽ là tương đương trong C - không kém vì không có tương đương trong môi trường C tiêu chuẩn. Và sự hiểu biết của tôi là công cụ tích hợp Perl 'người gọi' hoạt động từ ngăn xếp Perl hoặc dữ liệu liên quan đến chức năng gọi. –

0

Tôi đã viết thường trình backtrace cho các ứng dụng C (gcc) được nhúng của tôi. Nó sử dụng thông tin -gstabs nếu có sẵn để tra cứu tên hàm. Một lưu ý là tệp tin elf phải ở đâu đó mà chương trình có thể tìm thấy nó, để tìm trong đoạn stabs. Trong các ứng dụng nhúng của tôi, tập tin elf đang ngồi trong nháy mắt và tôi có một con trỏ đến nó. Trong trường hợp của bạn, bạn phải viết một số mã để đọc nó trong đĩa.

Tôi chắc chắn rằng tệp và số dòng cũng nằm trong phân đoạn stabs.

Điều này có vẻ giống như điều gì đó có thể giúp bạn không?

1

Có vẻ như không có gì tồn tại giống như mô-đun Cá chép để sử dụng trong các chương trình C, vì vậy tôi đã viết một thư viện nhỏ để làm điều đó tại github.

Thư viện có kim ngạch xuất khẩu sau được xác định để sử dụng:

warn, die 
carp, croak 
cluck, confess 

và tôi đã thêm e-giống của những người trước đó để thêm chuỗi errno để cảnh báo kể từ khi tôi nghĩ rằng nó sẽ có ích:

ewarn, edie 
ecarp, ecroak 
ecluck, econfess 

Ví dụ, nếu bạn đang viết một thư viện và muốn cá chép về một vấn đề, chỉ cần sử dụng

carp("%d is not a Fibonacci number!", 54); 

Và nó sẽ hiển thị các tập tin và số dòng của chức năng đầu tiên gọi vào thư viện của bạn.

Mô-đun Cá chép của Perl sử dụng một gói khác, thay vì tệp, để tìm chương trình con bị nghi ngờ. Nó cũng sử dụng mảng @ISA hoặc @CARP_NOT đệ quy để xác định chương trình con nào nằm ngoài nhóm đáng tin cậy của các gói. Tôi định thêm một cái gì đó tương tự như thế này. Nếu phần trên của stacktrace nằm trong phạm vi tin cậy, thì cá chép sẽ chuyển thành một cluck (hiển thị một stacktrace đầy đủ của vấn đề) giống như thư viện này sẽ làm.

+0

NB: Tính đến 2012-09-06, liên kết Github là 404. –