Surviving the Release Version

ASSERT and VERIFY

Many programmers put ASSERT macros liberally throughout their code. This is usually a good idea. The nice thing about the ASSERT macro is that using it costs you nothing in the release version because the macro has an empty body. Simplistically, you can imagine the definition of the ASSERT macro as being

#ifdef _DEBUG
#define ASSERT(x) if( (x) == 0) report_assert_failure()
#else
#define ASSERT(x)
#endif

(The actual definition is more complex, but the details don't matter here). This works fine when you are doing something like

ASSERT(whatever != NULL);

which is pretty simple, and omitting the computation of the test from the release version doesn't hurt. But some people will write things like

ASSERT( (whatever = somefunction() ) != NULL);

which is going to fail utterly in the release version because the assignment is never done, because there is no code generated (we will defer the discussion of embedded assignments being fundamentally evil to some other essay yet to be written. Take it as given that if you write an assignment statement within an if-test or any other context you are committing a serious programming style sin!)

Another typical example is

ASSERT(SomeWindowsAPI(...));

which will cause an assertion failure if the API call fails. But in the release version of the system the call is never made!

That's what VERIFY is for. Imagine the definitions of VERIFY as being

#ifdef _DEBUG
#define VERIFY(x) if( (x) == 0) report_assert_failure()
#else
#define VERIFY(x) (x)
#endif

Note this is a very different definition. What is dropped out in the release version is the if-test, but the code is still executed. The correct forms of the above incorrect examples would be

VERIFY((whatever = somefunction() ) != NULL);
VERIFY(SomeWindowsAPI(...));

This code will work correctly in both the debug and release versions, but in the release version there will be no ASSERT failure if the test comes out FALSE. Note that I've also seen code that looks like

VERIFY( somevalue != NULL);

which is just silly. What it effectively means is that it will, in release mode, generate code to compute the expression but ignore the result. If you have optimizations turned on, the compiler is actually clever enough to determine that you are doing something that has no meaning and discard the code that would have been generated (but only if you have the Professional or Enterprise versions of the compiler!). But as we also discuss in this essay, you can create an unoptimized release version, in which case the preceding VERIFY would simply waste time and space.

You might also like...

Comments

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“PHP is a minor evil perpetrated and created by incompetent amateurs, whereas Perl is a great and insidious evil perpetrated by skilled but perverted professionals.” - Jon Ribbens