Thêm thông điệp tùy chỉnh trong khẳng định?


129

Có cách nào để thêm hoặc chỉnh sửa tin nhắn được ném bởi khẳng định không? Tôi muốn sử dụng một cái gì đó như

assert(a == b, "A must be equal to B");

Sau đó, trình biên dịch thêm dòng , thời gian và vv ...

Có thể không?


Bạn có thể định nghĩa một macro, như thế này .
Goodbye

Câu trả lời:


240

Một hack tôi đã thấy xung quanh là sử dụng &&toán tử. Vì một con trỏ "là đúng" nếu nó không có giá trị, bạn có thể thực hiện các thao tác sau mà không thay đổi điều kiện:

assert(a == b && "A is not equal to B");

asserthiển thị điều kiện không thành công, nó cũng sẽ hiển thị thông báo của bạn. Nếu nó không đủ, bạn có thể viết myAsserthàm hoặc macro của riêng bạn sẽ hiển thị bất cứ thứ gì bạn muốn.


27
Một tùy chọn khác là đảo ngược toán hạng và sử dụng toán tử dấu phẩy. Bạn cần thêm dấu ngoặc đơn để dấu phẩy không được coi là dấu phân cách giữa các đối số:assert(("A must be equal to B", a == b));
Keith Thompson

3
Tuy nhiên, thật tuyệt khi có thể in các giá trị của các biến, như trong:assert(a == b && "A (" << A << ") is not equal to B (" << B << ")");
Frank

7
@Frank, printftrả về giá trị khác không nếu nó in bất cứ thứ gì, vì vậy bạn có thể làm một cái gì đó như thế assert(a == b && printf("a (%i) is not equal to b (%i)", a, b)), mặc dù tại thời điểm đó có lẽ bạn nên viết trình bao bọc khẳng định của riêng bạn.
zneak

1
Mã xấu! Tôi không hiểu điều này! Nếu a == b là sai, biểu thức và cũng sẽ sai và do đó, chuỗi không nên được ước tính.
ragnarius

1
@TUIlover, đó không phải là cách hoạt động của chuỗi C; chúng là các hằng số thời gian biên dịch và việc sử dụng chúng trong bối cảnh này được tối ưu hóa một cách tầm thường. Không có chi phí thời gian chạy.
zneak

45

Một tùy chọn khác là đảo ngược toán hạng và sử dụng toán tử dấu phẩy. Bạn cần thêm dấu ngoặc đơn để dấu phẩy không được coi là dấu phân cách giữa các đối số:

assert(("A must be equal to B", a == b));

(điều này đã được sao chép từ các ý kiến ​​trên, để nhìn rõ hơn)


3
Đây là một cách tiếp cận tuyệt vời, với một vấn đề nhỏ, nó sẽ hiển thị "cảnh báo: toán hạng bên trái của toán tử dấu phẩy không có tác dụng" khi được biên dịch trong g ++ với `-Wunuse-value
v010dya

1
hoặc với một macro: #ifndef m_assert #define m_assert (expr, dir) khẳng định ((tin nhắn, expr)) #endif
Szymon Marczak

Sử dụng trình bao bọc macro cho phép bạn tránh cảnh báo gcc:#define m_assert(expr, msg) assert(( (void)(msg), (expr) ))
Jander

25

Đây là phiên bản macro khẳng định của tôi, chấp nhận thông báo và in mọi thứ ra một cách rõ ràng:

#include <iostream>

#ifndef NDEBUG
#   define M_Assert(Expr, Msg) \
    __M_Assert(#Expr, Expr, __FILE__, __LINE__, Msg)
#else
#   define M_Assert(Expr, Msg) ;
#endif

void __M_Assert(const char* expr_str, bool expr, const char* file, int line, const char* msg)
{
    if (!expr)
    {
        std::cerr << "Assert failed:\t" << msg << "\n"
            << "Expected:\t" << expr_str << "\n"
            << "Source:\t\t" << file << ", line " << line << "\n";
        abort();
    }
}

Bây giờ, bạn có thể sử dụng này

M_Assert(ptr != nullptr, "MyFunction: requires non-null argument");

Và trong trường hợp thất bại, bạn sẽ nhận được một tin nhắn như thế này:

Khẳng định thất bại: MyFunction: yêu cầu đối số không null

Dự kiến: ptr! = Nullptr

Nguồn: C: \ MyProject \ src.cpp, dòng 22

Đẹp và sạch sẽ, hãy sử dụng nó trong mã của bạn =)


Đẹp một. Rất hữu ích
Killrazor

Tôi có chút bối rối. Là #Expr được coi là một chuỗi để thay thế trực tiếp? Sự khác biệt giữa #Expr và Expr là gì?
Minh Trần

@MinhTran Hãy giả sử rằng điều kiện khẳng định của bạn là x == y. Sau đó, Expr sẽ mở rộng vào if( !(x == y))và đây là nơi kiểm tra điều kiện và #Expr sẽ mở rộng thành chuỗi ký tự "x == y", sau đó chúng tôi đưa vào thông báo lỗi.
Eugene Magdalits

Thật không may, giải pháp này gây ra hành vi không xác định do sử dụng định danh dành riêng.
Hãy nhớ đến

19
BOOST_ASSERT_MSG(expre, msg)

http://www.boost.org/doc/libs/1_51_0/libs/utility/assert.html

Bạn có thể sử dụng trực tiếp hoặc sao chép mã của Boost. Cũng lưu ý Boost assert chỉ là tiêu đề, vì vậy bạn chỉ có thể lấy tệp đó nếu bạn không muốn cài đặt tất cả Boost.


@Jichao, ý của bạn là gì khi triển khai giao diện khẳng định?
Tarc

7

Khi câu trả lời của zneak làm xáo trộn phần nào mã, một cách tiếp cận tốt hơn là chỉ bình luận chuỗi văn bản bạn đang nói đến. I E.:

assert(a == b); // A must be equal to B

Vì người đọc lỗi xác nhận sẽ tìm kiếm tệp và dòng dù sao từ thông báo lỗi, họ sẽ thấy giải thích đầy đủ ở đây.

Bởi vì, vào cuối ngày, điều này:

assert(number_of_frames != 0); // Has frames to update

đọc tốt hơn thế này:

assert(number_of_frames != 0 && "Has frames to update");

về mặt phân tích cú pháp của con người tức là. khả năng đọc. Cũng không phải là một ngôn ngữ hack.


1
"Vì người đọc lỗi xác nhận sẽ tìm kiếm tệp và dòng dù sao từ thông báo lỗi" - chỉ khi họ siêng năng.
Jason S

Chỉ khi họ muốn sửa lỗi, ý bạn là ... một bình luận ngớ ngẩn
biến thái

1
Không. Bạn càng dễ dàng cho mọi người thấy vấn đề, họ càng có nhiều khả năng sẽ hành động.
Jason S

nhún vai không đồng ý.
biến thái

2

khẳng định là sự kết hợp vĩ mô / chức năng. bạn có thể xác định vĩ mô của riêng bạn / chức năng, sử dụng __FILE__, __BASE_FILE__, __LINE__vv, với chức năng riêng của mình mà phải mất một thông báo tùy chỉnh


-6

Đối với vc, thêm mã sau vào assert.h,

#define assert2(_Expression, _Msg) (void)( (!!(_Expression)) || (_wassert(_CRT_WIDE(#_Msg), _CRT_WIDE(__FILE__), __LINE__), 0) )

11
Sửa đổi tiêu đề biên dịch của bạn là ý tưởng tồi.
Ross Ridge
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.