debug - assertion failed c++ solucion
¿Cómo imprimir información adicional cuando falla el aserto? (9)
A menudo, uno quiere imprimir información adicional si una assert
falla. Una forma de hacerlo es esta:
assert(vec.size() > i ||
!(std::cerr << "False: " << vec.size() << ">" << i))
De esta manera, los tamaños reales se imprimen cuando falla la assert
. Pero es feo, y también es fácil olvidar el !
, lo que hará que la condición de aserción sea verdadera y el programa simplemente continuará.
¿Qué usa la gente en lugar de imprimir información adicional en caso de fallo de aserción, como arriba?
¿Qué usa la gente en lugar de imprimir información adicional en caso de fallo de aserción, como arriba?
En general, solo agregué un literal de cadena que describe el significado de la condición:
assert(v.size() > i && "The vector really needs to be larger");
Pero tal vez una macro como esta:
#include <cassert>
#include <vector>
#include <iostream>
//#define NDEBUG
#ifndef NDEBUG
#define ASSERT_EX(condition, statement) /
do { /
if (!(condition)) { statement; assert(condition); } /
} while (false)
#else
#define ASSERT_EX(condition, statement) ((void)0)
#endif
int main()
{
std::vector<int> v;
unsigned i = 1;
ASSERT_EX(v.size() > i, std::cerr << "i = " << i << ", v.size() = " << v.size() << ''/n'');
}
Sin embargo, aquí sería bueno si la statement
no tuviera efectos secundarios, cambiando la forma en condition
evalúa la condition
. :)
Creo que lo siguiente tiene sentido. En lugar de esto:
assert(vec.size() > i ||
!(std::cerr << "False: " << vec.size() << ">" << i))
sólo haz esto:
assert(vec.size() > i ||
assert_msg(vec.size() << ">" << i));
donde assert_msg
se define como algo como esto:
#define assert_msg(x) !(std::cerr << "Assertion failed: " << x << std::endl)
Esto es lo que uso, se rompe en la línea real que falló, en lugar de en otra parte de la pila. Funciona en MSVC y GCC, y utiliza un poco de magia mágica y genera un diálogo de afirmación:
#include <boost/current_function.hpp>
#if defined(NDEBUG)
# define MY_ASSERT(expr) ((void)0)
#else
int assertion_failed(char const *expr, char const *function, char const *file, long line);
# if defined(_WIN32)
# define debugbreak __debugbreak
# else
# define debugbreak __builtin_trap
# endif
# define MY_ASSERT(expr) ((expr) || !assertion_failed(#expr, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__) || (debugbreak(), 0))
#endif
#if !defined(NDEBUG)
int assertion_failed(char const *expr, char const *function, char const *file, long line)
{
#if defined(_WIN32)
return ::_CrtDbgReport(_CRT_ASSERT, file, line, NULL, "%s", expr);
# else
return !0;
# endif
}
#endif
Hice esto para C simple, basado en la respuesta de Notinlist (¡gracias!):
my_assert.c:
void _assert_int(char *astr, char *oper, char *bstr, int a, int b, char *file, int line) {
printf("/nAssertion failed: %s %s %s/n%s = %d/n%s = %d/nfile: %s/nline: %d/n", astr, oper, bstr, astr, a, bstr, b, file, line);
exit(1);
}
void _assert_str_equal(char *vara, char *varb, char *a, char *b, char *file, int line) {
if (a == b) {
#ifdef TREAT_BOTH_NULL_STRS_AS_ERROR
if (a != 0) return;
goto loc_failed;
#else
return;
#endif
}
if ((a == 0) || (b == 0) || (strcmp(a, b) != 0)) {
loc_failed:
printf("/nAssertion failed: %s == %s/n%s = %s/n%s = %s/nfile: %s/nline: %d/n", vara, varb, vara, a, varb, b, file, line);
exit(1);
}
}
my_assert.h:
#define TREAT_BOTH_NULL_STRS_AS_ERROR
#define assert_int(left,operator,right) do { if(!((left) operator (right))) _assert_int(#left, #operator, #right, left, right, __FILE__, __LINE__); } while (0)
#define assert_str_equal(left,right) do { _assert_str_equal(#left, #right, left, right, __FILE__, __LINE__); } while (0)
uso:
assert_int(a,==,b);
assert_str_equal(str1,str2);
Compruebe también el marco de prueba de la unidad del asiento
La mayoría de los controladores de aserción extendida son de la forma:
assert_x(CONDITION,EXPLANATION);
Lo que quieres es algo en la línea de
assert_args(condition, explanation, ...);
Asi que:
extern string build_assert_string(const string&, explanation, ...);
#define ASSERT_ARGS(CONDITION,build_assert_string EXPLANATION)
llamar como
ASSERT_ARGS(x > 0, ("x should be > 0 but it is %d", x));
La función build_assert_string es trivial.
Utilizo una instrucción if
o wxASSERT_MSG de wxWidgets .
Si usa un marco, vea si proporciona algunas herramientas de aserción útiles.
Yo uso algo como esto:
#define ASSERT(lhs, op, rhs) assert_template((lhs##op##rhs), "(" #lhs #op #rhs ")", lhs, rhs, __FILE__, __LINE__)
template <typename t1, typename t2>
void assert_template(const bool result, const char expr[], t1 lhs, t2 rhs, const char file_name[], const long line_number)
{
if (!result)
{
std::cerr << "Assertion failed";
std::cerr << " " << expr;
std::cerr << " lhs = " << lhs;
std::cerr << " rhs = " << rhs;
std::cerr << " File: /"" << file_name << "/"";
std::cerr << " Line: " << std::dec << line_number;
throw "Assertion failed";
}
};
La sintaxis de uso es un poco rara como en ASSERT(vec.size(), >, 1)
o ASSERT(error, ==, 0)
. La ventaja es que también imprime los valores del lado izquierdo y derecho. En Windows también me gusta lanzar GetLastError () y WSAGetLastError ().
assert () compila a la nada en la versión de lanzamiento de muchos compiladores. No es algo que tenga algún valor para el código de producción.
Yo uso una construcción como esta:
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <ctime>
#include <iostream>
using namespace std;
template<typename T> inline bool Verify(T const& t,char const* Expression, char const* File, unsigned long Line)
{
bool b = !(!t);
if( b )
return true;
// verify failed -- report it
std::cerr << "Assertion ''" << Expression << "'' Failed @ " << File << ":" << Line << endl;
return false;
};
#define verify(exp) (bool)( Verify(exp, #exp, __FILE__, __LINE__) )
template<typename Iter> void doit(Iter const begin, const Iter & end)
{
for( ; begin != end; ++begin )
;
}
int main()
{
int n = 1;
n *= 2;
verify( n == 3 );
return 0;
}
Salida del programa:
Assertion ''n == 3'' Failed @ ./main.cpp:32
#define ASSERT(condition) { if(!(condition)){ std::cerr << "ASSERT FAILED: " << #condition << " @ " << __FILE__ << " (" << __LINE__ << ")" << std::endl; } }
Uso:
ASSERT(vec.size()>1);
Resultado:
ASSERT FAILED: vec.size()>1 @ main.cpp (17)
Opcionalmente, puede poner DebugBreak()
o exit(-1)
o watever en la macro, según sus necesidades.
Macro actualizada con lado izquierdo y derecho separados:
#define ASSERT(left,operator,right) { if(!((left) operator (right))){ std::cerr << "ASSERT FAILED: " << #left << #operator << #right << " @ " << __FILE__ << " (" << __LINE__ << "). " << #left << "=" << (left) << "; " << #right << "=" << (right) << std::endl; } }
Uso:
ASSERT(a,>,b);
Resultado:
ASSERT FAILED: a>b @ assert2.cpp (8). a=3; b=4