Hack, który widziałem, polega na użyciu &&operatora. Ponieważ wskaźnik „jest prawdziwy”, jeśli nie jest zerowy, możesz wykonać następujące czynności bez zmiany warunku:
assert(a == b && "A is not equal to B");
Ponieważ assertpokazuje stan, który się nie powiódł, wyświetli również Twoją wiadomość. Jeśli to nie wystarczy, możesz napisać własną myAssertfunkcję lub makro, które wyświetli, co chcesz.
Inną opcją jest odwrócenie operandów i użycie operatora przecinka. Potrzebujesz dodatkowych nawiasów, aby przecinek nie był traktowany jako separator między argumentami:assert(("A must be equal to B", a == b));
Keith Thompson,
3
Fajnie byłoby jednak móc wydrukować wartości zmiennych, jak w:assert(a == b && "A (" << A << ") is not equal to B (" << B << ")");
Frank
7
@Frank, printfzwraca wartość niezerową, jeśli coś wypisuje, więc możesz zrobić coś podobnego assert(a == b && printf("a (%i) is not equal to b (%i)", a, b)), chociaż w tym momencie prawdopodobnie powinieneś napisać własne opakowanie assert.
zneak
1
Zły kod! Nie rozumiem tego! Jeśli a == b jest fałszem, wyrażenie and powinno również mieć wartość fałsz, a zatem ciąg nie powinien być oceniany.
ragnarius
2
@TUIlover, nie tak działają literały ciągów C; są stałymi czasu kompilacji i ich użycie w tym kontekście jest banalnie zoptymalizowane. Nie ma żadnych kosztów działania.
zneak
48
Inną opcją jest odwrócenie operandów i użycie operatora przecinka. Potrzebujesz dodatkowych nawiasów, aby przecinek nie był traktowany jako separator między argumentami:
assert(("A must be equal to B", a == b));
(to zostało skopiowane z powyższych komentarzy, dla lepszej widoczności)
Jest to świetne podejście, z jednym drobnym problemem, wyświetli "ostrzeżenie: lewy operand operatora przecinka nie ma wpływu" po skompilowaniu w g ++ z `-Wunused-value
v010dya
1
lub z makrem: #ifndef m_assert #define m_assert (expr, msg) assert ((msg, expr)) #endif
Szymon Marczak
Korzystanie z opakowania makr pozwala uniknąć ostrzeżenia gcc:#define m_assert(expr, msg) assert(( (void)(msg), (expr) ))
Jander
26
Oto moja wersja makra assert, które akceptuje wiadomość i wyświetla wszystko w przejrzysty sposób:
Jestem trochę zdezorientowany. Czy #Expr jest traktowane jako ciąg do bezpośredniego podstawienia? Jaka jest różnica między #Expr i Expr?
Minh Tran
@MinhTran Załóżmy, że warunek potwierdzenia to x == y. Następnie Expr rozwinie się do if( !(x == y))i tutaj sprawdzany jest warunek, a #Expr rozwinie się do literału ciągu "x == y", który następnie umieścimy w komunikacie o błędzie.
Eugene Magdalits,
Niestety to rozwiązanie powoduje niezdefiniowane zachowanie z powodu używania zarezerwowanych identyfikatorów.
Możesz użyć tego bezpośrednio lub skopiować kod Boost. Zwróć również uwagę, że potwierdzenie Boost jest tylko nagłówkiem, więc możesz po prostu pobrać ten pojedynczy plik, jeśli nie chcesz instalować całego Boost.
„Ponieważ czytelnik potwierdzenia błędu i tak przejrzy plik i wiersz w komunikacie o błędzie” - tylko wtedy, gdy jest sumienny.
Jason S
Tylko jeśli chcą naprawić błąd, który masz na myśli ... co za głupi komentarz
metamorfoza
2
Nie. Im łatwiej sprawisz, że ludzie zobaczą problem, tym większe prawdopodobieństwo, że podejmą działania.
Jason S
wzruszenie ramionami Nie zgadzam się.
metamorfoza
2
assert jest kombinacją makra / funkcji. można zdefiniować własne makro / funkcję, za pomocą __FILE__, __BASE_FILE__, __LINE__itp, z własnej funkcji, które ma niestandardowy komunikat
Możesz także po prostu napisać własną niestandardową funkcję assert. Bardzo prosty przykład:
boolprint_if_false(constbool assertion, constchar* msg){
if(!assertion) {
// endl to flushstd::cout << msg << std::endl;
}
return assertion;
}
intmain(){
int i = 0;
int j = 1;
assert(print_if_false(i == j, "i and j should be equal"));
return0;
}
Odpowiedzi:
Hack, który widziałem, polega na użyciu
&&
operatora. Ponieważ wskaźnik „jest prawdziwy”, jeśli nie jest zerowy, możesz wykonać następujące czynności bez zmiany warunku:assert(a == b && "A is not equal to B");
Ponieważ
assert
pokazuje stan, który się nie powiódł, wyświetli również Twoją wiadomość. Jeśli to nie wystarczy, możesz napisać własnąmyAssert
funkcję lub makro, które wyświetli, co chcesz.źródło
assert(("A must be equal to B", a == b));
assert(a == b && "A (" << A << ") is not equal to B (" << B << ")");
printf
zwraca wartość niezerową, jeśli coś wypisuje, więc możesz zrobić coś podobnegoassert(a == b && printf("a (%i) is not equal to b (%i)", a, b))
, chociaż w tym momencie prawdopodobnie powinieneś napisać własne opakowanie assert.Inną opcją jest odwrócenie operandów i użycie operatora przecinka. Potrzebujesz dodatkowych nawiasów, aby przecinek nie był traktowany jako separator między argumentami:
assert(("A must be equal to B", a == b));
(to zostało skopiowane z powyższych komentarzy, dla lepszej widoczności)
źródło
#define m_assert(expr, msg) assert(( (void)(msg), (expr) ))
Oto moja wersja makra assert, które akceptuje wiadomość i wyświetla wszystko w przejrzysty sposób:
#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(); } }
Teraz możesz tego użyć
M_Assert(ptr != nullptr, "MyFunction: requires non-null argument");
A w przypadku niepowodzenia otrzymasz taki komunikat:
Ładnie i czysto, możesz użyć go w swoim kodzie =)
źródło
x == y
. Następnie Expr rozwinie się doif( !(x == y))
i tutaj sprawdzany jest warunek, a #Expr rozwinie się do literału ciągu"x == y"
, który następnie umieścimy w komunikacie o błędzie.http://www.boost.org/doc/libs/1_51_0/libs/utility/assert.html
Możesz użyć tego bezpośrednio lub skopiować kod Boost. Zwróć również uwagę, że potwierdzenie Boost jest tylko nagłówkiem, więc możesz po prostu pobrać ten pojedynczy plik, jeśli nie chcesz instalować całego Boost.
źródło
Ponieważ odpowiedź zneak nieco zawija kod, lepszym podejściem jest po prostu skomentowanie tekstu ciągu, o którym mówisz. to znaczy.:
assert(a == b); // A must be equal to B
Ponieważ czytelnik błędu assert i tak odszuka plik i wiersz z komunikatu o błędzie, zobaczy tutaj pełne wyjaśnienie.
Ponieważ pod koniec dnia:
assert(number_of_frames != 0); // Has frames to update
czyta lepiej niż to:
assert(number_of_frames != 0 && "Has frames to update");
pod względem analizy kodu przez człowieka, tj. czytelność. Nie jest to też hack językowy.
źródło
assert jest kombinacją makra / funkcji. można zdefiniować własne makro / funkcję, za pomocą
__FILE__
,__BASE_FILE__
,__LINE__
itp, z własnej funkcji, które ma niestandardowy komunikatźródło
Możesz także po prostu napisać własną niestandardową funkcję assert. Bardzo prosty przykład:
bool print_if_false(const bool assertion, const char* msg) { if(!assertion) { // endl to flush std::cout << msg << std::endl; } return assertion; } int main() { int i = 0; int j = 1; assert(print_if_false(i == j, "i and j should be equal")); return 0; }
bawić się kodem.
Twierdzenie brzmi
Assertion print_if_false(i == j, "i and j should be equal")
.źródło
W przypadku vc dodaj następujący kod w assert.h,
#define assert2(_Expression, _Msg) (void)( (!!(_Expression)) || (_wassert(_CRT_WIDE(#_Msg), _CRT_WIDE(__FILE__), __LINE__), 0) )
źródło