Додати власні повідомлення у ствердженні?


129

Чи є спосіб додати чи відредагувати повідомлення, викинуте шляхом assrt? Я хотів би використати щось подібне

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

Потім компілятор додає рядок , час і так далі ...

Це можливо?


Ви можете визначити такий макрос, як цей .
HelloGoodbye

Відповіді:


240

Злом, який я бачив, - це використовувати &&оператора. Оскільки вказівник "true", якщо він не є null, ви можете зробити наступне, не змінюючи умови:

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

Оскільки assertвідображається умова, що не вдалося, воно відобразить і ваше повідомлення. Якщо цього недостатньо, ви можете написати власну myAssertфункцію або макрос, який відображатиме все, що завгодно.


27
Інший варіант - повернути операнди та використовувати оператор комами. Вам потрібні додаткові дужки, тому кома не розглядається як роздільник між аргументами:assert(("A must be equal to B", a == b));
Кіт Томпсон

3
Було б непогано мати можливість надрукувати значення змінних, як у:assert(a == b && "A (" << A << ") is not equal to B (" << B << ")");
Франк

7
@Frank, printfповертає ненульове значення, якщо він щось надрукував, тож ви могли б зробити щось на кшталт assert(a == b && printf("a (%i) is not equal to b (%i)", a, b)), хоча в цей момент ви, мабуть, повинні написати власну обгортку затвердження.
zneak

1
Поганий код! Я цього не розумію! Якщо a == b невірно, а-вираз також повинен бути хибним, і, отже, рядок не слід оцінювати.
ragnarius

1
@TUIlover, це не так, як працюють літеральні рядки C; вони константи часу компіляції, і їх використання в цьому контексті тривільно оптимізовано. Витрат на виконання немає.
zneak

45

Інший варіант - повернути операнди та використовувати оператор комами. Вам потрібні додаткові дужки, щоб кома не розглядалася як роздільник між аргументами:

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

(це було скопійовано з вищезазначених коментарів для кращої наочності)


3
Це чудовий підхід, при одному крихітному питанні він буде відображати "попередження: лівий операнд оператора кома не має ефекту" при компілюванні в g ++ з `-Wunused-value
v010dya

1
або з макросом: #ifndef m_assert #define m_assert (expr, msg) assert ((msg, expr)) #endif
Szymon Marczak

Використання обгортки макросу дозволяє уникнути попередження gcc:#define m_assert(expr, msg) assert(( (void)(msg), (expr) ))
Jander

25

Ось моя версія макросу assert, який приймає повідомлення і чітко роздруковує все:

#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();
    }
}

Тепер ви можете цим скористатися

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

А в разі відмови ви отримаєте таке повідомлення:

Сертифікат не вдався: MyFunction: вимагає ненульового аргументу

Очікується: ptr! = Nullptr

Джерело: C: \ MyProject \ src.cpp, рядок 22

Приємно і чисто, не соромтеся використовувати його у своєму коді =)


Хороший. Дуже корисно
Killrazor

Я трохи розгублений. Чи #Expr трактується як рядок для прямої підстановки? Яка різниця між #Expr та Expr?
Мінь Тран

@MinhTran Припустимо, що ваша умова ствердження така x == y. Потім Expr розшириться, if( !(x == y))і тут перевіряється умова, а #Expr перетвориться на рядковий літерал "x == y", який ми потім вводимо в повідомлення про помилку.
Євген Магдалиць

На жаль, це рішення викликає не визначену поведінку через використання зарезервованих ідентифікаторів.
Згадайте Моніку

19
BOOST_ASSERT_MSG(expre, msg)

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

Ви можете використовувати це безпосередньо або скопіювати код Boost. Також зауважте, що Boost assert є лише заголовком, так що ви можете просто захопити цей єдиний файл, якщо ви не хочете встановити весь Boost.


@Jichao, що ти маєш на увазі під реалізацією інтерфейсу assert?
Тарч

7

Оскільки відповідь zneak дещо змінює код, кращим підходом є просто коментувати текст рядка, про який ви говорите. тобто .:

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

Оскільки читач помилки утвердження буде шукати файл і рядок все одно з повідомлення про помилку, тут він побачить повне пояснення.

Тому що, наприкінці дня, це:

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

читає краще за це:

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

з точки зору людського розбору коду, тобто. читабельність. Також не мовний злом.


1
"Оскільки читач помилки утвердження буде шукати файл і рядок все одно з повідомлення про помилку", - лише якщо вони старанні.
Джейсон S

Тільки якщо вони хочуть виправити помилку, ти маєш на увазі… який дурний коментар
метаморфоза

1
Ні. Чим легше ви зрозумієте проблему, тим більше шансів вони вжити заходів.
Jason S

знизати плечима Не погоджуючись.
метаморфоза

2

assrt - комбінація макро / функцій. ви можете визначити свій власний макро / функцію, використовуючи__FILE__ , __BASE_FILE__, і __LINE__т.д., з вашої власної функції , яка приймає призначене для користувача повідомлення


-6

Для vc додайте наступний код у assert.h,

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

11
Змінити заголовки компілятора - це погана ідея.
Росс Ридж
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.