2009-03-24 52 views
33

Sau nhiều năm sử dụng macro MFC ASSERT xấu xí lớn, cuối cùng tôi đã quyết định bỏ nó và tạo macro ASSERT cuối cùng.Làm thế nào để tìm tên của hàm hiện tại trong thời gian chạy?

Tôi ổn khi nhận được tệp và số dòng, và thậm chí cả biểu thức không thành công. Tôi có thể hiển thị một hộp thông báo với các nút này và các nút Hủy bỏ/Thử lại/Hủy.

Và khi tôi nhấn Thử lại trình gỡ lỗi VS sẽ nhảy vào dòng chứa lệnh gọi ASSERT (trái ngược với việc tháo gỡ ở đâu đó giống như một số hàm ASSERT khác). Vì vậy, đó là tất cả khá nhiều làm việc.

Nhưng điều thực sự thú vị sẽ là hiển thị tên của hàm không thành công.

Sau đó, tôi có thể quyết định xem có nên gỡ lỗi nó mà không cố gắng đoán chức năng của nó trong tên tệp hay không.

ví dụ: nếu tôi có chức năng sau:

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{ 
    ASSERT(lpCreateStruct->cx > 0); 
    ... 
} 

Sau đó, khi các đám cháy khẳng định, các bảng thông báo sẽ hiển thị một cái gì đó như:

Function = CMainFrame::OnCreate 

Vì vậy, cách đơn giản nhất của việc tìm ra tên hàm hiện nay là gì, tại thời gian chạy?

Không nên sử dụng MFC hoặc khung .NET, mặc dù tôi sử dụng cả hai.
Nó phải càng di động càng tốt.

+0

Nếu bạn có quyền truy cập vào [Ứng dụng gỡ lỗi cho Microsoft® .NET và Microsoft Windows® của John Robbins] (http://www.amazon.com/Debugging-Applications-Microsoft®-Microsoft-Pro-Developer/dp/0735615365/ref = sr_1_16/175-5814253-7853112? Ie = UTF8 & s = điện tử & qid = 1237928779 & sr = 8-16) bạn chắc chắn nên xem xét các xác nhận từ thư viện BugSlayerUtil trên CD được cung cấp. Chúng đặc trưng cho Windows, nhưng thực sự là tối thượng. – Paul

+0

Tôi đã xem http://www.koders.com/cpp/fid3653A5E08C30DB8B7551729FBED0BC3D51B19AD8.aspx nhưng dường như không hiển thị tên hàm. Do đó tôi nghĩ rằng phiên bản của tôi là cuối cùng hơn của mình: D – demoncodemonkey

+0

Nó cho thấy stacktrace. Stacktrace chứa tên hàm, phải không? – Paul

Trả lời

48

Macro của bạn có thể chứa macro __FUNCTION__. Đừng nhầm lẫn, tên hàm sẽ được chèn vào mã mở rộng tại thời gian biên dịch, nhưng nó sẽ là tên hàm chính xác cho mỗi cuộc gọi đến macro của bạn. Vì vậy, "có vẻ như" nó xảy ra trong thời gian chạy;)

ví dụ:

#define THROW_IF(val) if (val) throw "error in " __FUNCTION__ 

int foo() 
{ 
    int a = 0; 
    THROW_IF(a > 0); // will throw "error in foo()" 
} 
+4

Thật không may, '__FUNCTION__' không phải là tiêu chuẩn. '__func__' * là * tiêu chuẩn, nhưng nó không phải là một chuỗi chữ; nó hoạt động như một biến, vì vậy bạn không thể nối nó dễ dàng. – ephemient

+0

. nhưng may mắn là OP đang sử dụng MFC và do đó, cross-platformness có lẽ không phải là một vấn đề. –

+2

Tôi đã đề cập nó vì OP đã yêu cầu tính di động. – ephemient

18

C++ Preprocessor vĩ mô __FUNCTION__ cho tên của hàm.

Lưu ý rằng nếu bạn sử dụng, nó không phải là thực sự nhận tên tệp, số dòng hoặc tên hàm khi chạy. Macro được mở rộng bởi bộ tiền xử lý và được biên dịch.

Macro __FUNCTION__, như __LINE____FILE__, là một phần của tiêu chuẩn ngôn ngữ và có thể di chuyển.

Ví dụ chương trình:

#include <iostream> 
#using namespace std; 

void function1() 
{ 
     cout << "my function name is: " << __FUNCTION__ << "\n"; 
} 
int main() 
{ 
     cout << "my function name is: " << __FUNCTION__ << "\n"; 
     function1(); 
     return 0; 
} 

đầu ra:

 
my function name is: main 
my function name is: function1 
+0

__FUNCTION__ không phải là một phần của tiêu chuẩn ngôn ngữ C++ (tôi đã không downvote yoou cho điều này, nhưng tôi đoán ai đó đã làm) –

+0

điểm tốt, tôi nghĩ rằng tôi hiểu sai một cái gì đó. theo http://gcc.gnu.org/onlinedocs/gcc/Function-Names.html, __func__ là một phần của tiêu chuẩn C99 (mặc dù không nhất thiết mọi thứ đều hỗ trợ nó). __FUNCTION__ là không, mặc dù nếu các compliers lớn (MSDN/GCC) hỗ trợ nó, nó có hiệu quả di động. – YenTheFirst

+1

Lưu ý rằng __func__ cũng không thuộc C++. –

4

Bạn có thể sử dụng __FUNCTION__ macro đó có ít thời gian biên dịch sẽ được mở rộng đến tên của hàm.

Dưới đây là ví dụ về cách sử dụng nó trong macro khẳng định.

#define ASSERT(cond) \ 
    do { if (!(cond)) \ 
    MessageBoxFunction("Failed: %s in Function %s", #cond, __FUNCTION__);\ 
    } while(0) 

void MessageBoxFunction(const char* const msg, ...) 
{ 
    char szAssertMsg[2048]; 

    // format args 
    va_list vargs; 
    va_start(vargs, msg); 
    vsprintf(szAssertMsg, msg, vargs); 
    va_end(vargs); 

    ::MessageBoxA(NULL, szAssertMsg, "Failed Assertion", MB_ICONERROR | MB_OK); 
} 
+0

Argh tại câu trả lời "..." nhưng nếu không tốt, cảm ơn. – demoncodemonkey

+0

lý do tại sao bạn phải ghét trên '...'? Đó là mã hợp lệ. –

+0

@demoncodemonkey: Trevor hỏi một câu hỏi rất. Tại sao Andrew không nên sử dụng hàm variadic ở đây? – unforgettableid

18

Không có giải pháp chuẩn. Tuy nhiên, BOOST_CURRENT_FUNCTION là thiết bị di động cho mọi mục đích thực tế. Tiêu đề không phụ thuộc vào bất kỳ tiêu đề Tăng cường nào khác, vì vậy có thể được sử dụng độc lập nếu không thể chấp nhận phí trên toàn bộ thư viện.

+1

Cảm ơn, tôi không sử dụng Boost (chưa) nhưng ít nhất tôi biết có một thay thế cho __FUNCTION__ nếu tôi có nhu cầu chuyển nó. – demoncodemonkey

+0

Tiêu đề cho {{BOOST_CURRENT_FUNCTION}} là độc lập. Bạn chỉ có thể tải xuống và đặt nó vào trong codebase của bạn mà không cần bất kỳ thứ gì khác từ Boost. –

7

Trong GCC, bạn có thể sử dụng macro __PRETTY_FUNCTION__.
Microsoft cũng có macro tương đương __func__ mặc dù tôi không có sẵn để thử.

ví dụ: sử dụng __PRETTY_FUNCTION__ đặt một cái gì đó như thế này vào lúc bắt đầu các chức năng của bạn và bạn sẽ nhận được một dấu vết hoàn

void foo(char* bar){ 
    cout << __PRETTY_FUNCTION__ << std::endl 
} 

mà sẽ ra

void foo(char* bar) 

Bạn cũng có __FILE____LINE__ macro có sẵn trong mọi tiêu chuẩn Trình biên dịch c/C++ nếu bạn muốn xuất nhiều thông tin hơn.

Trong thực tế, tôi có một lớp gỡ lỗi đặc biệt mà tôi sử dụng thay vì cout. Bằng cách xác định các biến môi trường thích hợp, tôi có thể nhận được một dấu vết chương trình đầy đủ. Bạn có thể làm một cái gì đó tương tự. Các macro này cực kỳ tiện dụng và thực sự tuyệt vời để có thể bật gỡ lỗi chọn lọc như thế này trong trường.

CHỈNH SỬA: dường như __func__ là một phần của tiêu chuẩn? không biết điều đó. Thật không may, nó chỉ cung cấp cho tên hàm và không phải là các tham số. Tôi thích số __PRETTY_FUNC__ của gcc nhưng không thể chuyển sang các trình biên dịch khác.

GCC cũng hỗ trợ __FUNCTION__.

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