#include "EAAssert/eaassert.h"
And get the following macros...
EA_ASSERT(expr) where
expr is an expression that evaluates to a boolean. For
example...
EA_ASSERT(3 != 5);
EA_ASSERT_MSG(expr, msg) where
msg is an string (i.e., a char*).
For example...
EA_ASSERT_MSG(3 != 5, "mathematics is flawed");
EA_ASSERT_FORMATTED(expr, fmt) where
fmt is a parentheses wrapped tuple of
which the first parameter is a string (i.e., a char*)
and the rest are printf style
parameters. For example...
EA_ASSERT_FORMATTED(3 != 5, ("The answer is: %d", 42));
EA_FAIL() similar to
EA_ASSERT(false)
but avoids warning of constant conditional expression.
EA_FAIL_MSG(msg) similar to
EA_ASSERT_MSG(false, msg);
EA_FAIL_FORMATTED(fmt) similar to
EA_ASSERT_FORMATTED(false, fmt);EA_ASSERT is enabled hinges on the following logic...
#ifdef EA_DEBUG
#define EA_ASSERT_ENABLED
#endif
#ifndef EA_ASSERT
#if EA_ASSERT_ENABLED
#define EA_ASSERT(expr) ...definition of EA_ASSERT...
#else
#define EA_ASSERT(expr) ((void)0)
#endif
#endif
To use EA_ASSERT in your own code you just include the header and use it.
To overwrite the default handler for assert failure, you need to implement the following function
bool EAAssertFailure(
const char* expr, // Stringized version of the assert expression.
const char* filename, // Name of the file in which the assert occured.
int line, // Line number on which the assert occured.
const char* function, // Name of the function the assert occured in.
const char* msg, // Optional descriptive message.
va_list args // Variable argument list (printf style) in case msg contains formatters.
);
The return value of this function should be true
if you want the failed assert to break into the debugger and
false
if you want to continue running past the assert.
To enable the use of this function, use:
EA::Assert::SetFailureCallback(&yourCallback);
The simplest possible implementation of this function (which happens to be the default) just returns true immediately, always triggering a debug break.
For reference, here's an example implementation of EAAssertFailure
that you can copy paste into your own code.
bool EAAssertFailure(const char* expr, const char* filename, int line, const char* function, const char* msg, va_list args)
{
const int size = 1024;
char output[size + 1] = {};
char fmtMsg[size + 1] = {};
_vsnprintf(fmtMsg, size, msg, args);
_snprintf(output, size, "%s(%d) : assert failed: '%s' in function: %s\n, message: %s", filename, line, expr, function, fmtMsg);
printf(output);
return true;
}
EA_ASSERT
to your own implementation. The trick is in the #EA_ASSERT_HAVE_OWN_HEADER
macro. Define this to the name of your own header file that has equivalents of
the macros defined above (make sure you provide all of them). For example, you
could put the following in a file called "game/my_own_awesome_assert.h"...
#define EA_ASSERT(expr) MY_OWN_AWESOME_ASSERT(expr)
#define EA_ASSERT_MSG(expr, msg) MY_OWN_AWESOME_ASSERT(expr)
#define EA_ASSERT_FORMATTED(expr, fmt) MY_OWN_AWESOME_ASSERT(expr)
#define EA_FAIL() MY_OWN_AWESOME_ASSERT(false)
#define EA_FAIL_MSG(msg) MY_OWN_AWESOME_ASSERT(false)
#define EA_FAIL_FORMATTED(fmt) MY_OWN_AWESOME_ASSERT(false)
Next, define #EA_ASSERT_HAVE_OWN_HEADER
to "game/my_own_awesome_assert.h" (including
the quotes) when you build EA_ASSERT using
technology and it will automatically use your assert instead.
EA_WARNING macros?Because few people can use warnings properly. This often results in games spewing so much output to the console that nobody cares anymore. If the problem is serious enough, just assert. If it's not serious enough, put a bright pink texture on it in the game.
EA_WARNING, can't
you add it?The truth is, the original author of this package didn't need them. Warning support would increase the complexity of this package of proportion (now you need warning levels, etc.) If you need warnings, write your own.
EA_ASSERT
macro and others, now what?Use the EA_ASSERT_HAVE_OWN_HEADER
feature described above. Now any library that uses EA_ASSERT
automatically leverages your assert.
This often occurs when you have asserts in a tight inner loop that
you only want enabled every now and then when you do very strict integrity
checking. Unfortunately it would complicate this library too much. We don't
feel enough technologies have a need for this. Fortunately you can implement
this yourself fairly easily by doing...
#if MY_TECH_DEBUG_LEVEL == 1
#define MY_TECH_ASSERT(expr) EA_ASSERT(expr)
#define MY_TECH_HARDCORE_ASSERT(expr) ((void)0)
#else if MY_TECH_DEBUG_LEVEL == 1
#define MY_TECH_ASSERT(expr) EA_ASSERT(expr)
#define MY_TECH_HARDCORE_ASSERT(expr) EA_ASSERT(expr)
#endif
That way you can still leverage EA_ASSERT
but have more fine grained control over assert subsets in your technology.
Because it would make things more complicated than I'd like. Furthermore, ignorable asserts often flawed. People end up using them to signal user errors that should be handled differently (proper fallback mechanisms, bright pink textures, etc.). What happens is that everybody starts ignoring asserts when they happen rather than fixing them or reporting them. You get away with this for a while, until one day shit hits the fan. Asserts are for programmer error, exceptions and other mechanisms are for user error.
That said if you desperately need ignorable asserts, all is not lost. Either use
the #EA_ASSERT_HAVE_OWN_HEADER feature,
or simply catch the filename and line-number in the handler function. Stick
them as a pair into a set. Whenever you find them in the set, return false from
the assert handler to ignore the assert.
I don't know. Let me know what its break-into-debugger statement is and I'll gladly add it.
Probably because I didn't need it. Alternatively, because it would make this package more complicated than I'd like. Perhaps feature X is best implemented in your own technology? Of course, you can always try sending us an email. Maybe we'll add feature X.