Must evaluate assertion?

F

Frederick Gotham

Irrespective of whether NDEBUG is defined, must an assertion expression
always be evaluated? For instance, is the following code perfectly OK?

#define NDEBUG

#include <assert.h>

int main(void)
{
int array[5];

int *p = array + 5;

assert(--p);

*p = 3;

return 0;
}

Is it wise to rely on the evaluation of assertion expressions, or would it
be better to move any side-effects to outside of the assertion, such as:

--p; assert(p);

instead of:

assert(--p);
 
S

Szabolcs Borsanyi

Frederick Gotham asked:
Irrespective of whether NDEBUG is defined, must an assertion expression
always be evaluated? For instance, is the following code perfectly OK?

#define NDEBUG

#include <assert.h>
int main(void)
{
int array[5];
int *p = array + 5;
assert(--p);
*p = 3;

return 0;
}

The standard (c99) says:
If NDEBUG is defined as a macro name at the
point in the source file where<assert.h>is included,
the assert macro is defined simply as
#define assert(ignore) ((void)0)

So, the argument is not evaluated, (assert is a macro and not a
function). As this behaviour is mandatory, it is very easy to check.


Szabolcs Borsanyi

Correct me if I get it wrong.
 
E

Eric Sosman

Frederick said:
Irrespective of whether NDEBUG is defined, must an assertion expression
always be evaluated? [...]

Is it wise to rely on the evaluation of assertion expressions, or would it
be better to move any side-effects to outside of the assertion, such as:

--p; assert(p);

instead of:

assert(--p);

Use the former, not the latter. It is UNwise to have
side-effects in an assert-ed expression.
 
M

Michael Mair

Frederick said:
Irrespective of whether NDEBUG is defined, must an assertion expression
always be evaluated? For instance, is the following code perfectly OK?

No, and no. Others have already told you that.
Is it wise to rely on the evaluation of assertion expressions, or would it
be better to move any side-effects to outside of the assertion, such as:

--p; assert(p);

instead of:

assert(--p);

The first way certainly is better than the second in that it
always leads to the same programme behaviour.
Note that in C90, assert expects an integer expression as argument,
so the above can fail for p of pointer type.

I rather discourage the use of assert in your main control flow.
Consider this:
if (....)
{
/* Should not happen */
INTERNAL_ASSERT(0);
EmitInternalFatal(....);
CleanupAndDie();
}
or
....
default:
INTERNAL_ASSERT(0, "D\'uh!");
EmitExternalFatal(....);
....
where the customer gets the version where INTERNAL_ASSERT
does not do anything and the developers the version where it
makes the debugger stop (this version difference can be a
hidden option). This way, the users get a clean abort and you
get help for debugging.
This is one of the uses most people can agree to.
There have been several long discussions on clc about just
how to use assert -- just read them in the archives.


Cheers
Michael
 
S

Szabolcs Borsanyi

I rather discourage the use of assert in your main control flow.

I know, there were long discussions in this subject already, still
I'd like to comment the remark above:
assertation is not only a bug-catching tool (as opposed to error-catching),
but some compilers recognize it as an optimization aid.
The assert macro provides a portable way to enable the SIMD instruction
set by telling the compiler that an object is sufficiently aligned.
In this case, the assert macro should appear in the main flow.
(I used this with the intel compiler).

Szabolcs Borsanyi
 
R

Richard Heathfield

Frederick Gotham said:
Irrespective of whether NDEBUG is defined, must an assertion expression
always be evaluated?

No. See 4.2:

"If NDEBUG is defined as a macro name at the point in the source file where
<assert.h> is included, the assert macro is defined simply as

#define assert(ignore) ((void)0)"

<snip>
 
S

Skarmander

Szabolcs said:
I know, there were long discussions in this subject already, still
I'd like to comment the remark above:
assertation is not only a bug-catching tool (as opposed to error-catching),
but some compilers recognize it as an optimization aid.
The assert macro provides a portable way to enable the SIMD instruction
set by telling the compiler that an object is sufficiently aligned.

How, exactly? I can't think of a way to portably express alignment
requirements offhand, but I'll admit I have no experience with such matters
either. (I don't question that you can use assert() to portably convey
optimization hints, and it's actually a sensible application, if not what C
programs usually use it for.)

S.
 
S

Szabolcs Borsanyi

How, exactly? I can't think of a way to portably express alignment requirements
offhand, but I'll admit I have no experience with such matters either. (I don't
question that you can use assert() to portably convey optimization hints, and
it's actually a sensible application, if not what C programs usually use it
for.)

Well, OK, my macro below is not portable, since casting a pointer to
an unsigned long could go wrong. But I could have used the intptr_t type
as well, and I am not worried about overflow if the alignment information
is my only wish.
(Criticism, better suggestions welcome, maybe in a separate thread)

#define assert_alignment(ptr) assert(((unsigned long)(ptr)&(2*sizeof(double)-1))
==0)

And I have to admit that I did not test whether or not the following
construct would result in the desired optimized code:
if(alignment_check) {
...code... /* probably compiled with SIMD instruction set */
} else {
.... same code ... /* not optimized */
}

An then it could even work without the 'ugly' assert macro, but I've never
tried.

Szabolcs Borsanyi
 
G

Guest

Skarmander said:
How, exactly? I can't think of a way to portably express alignment
requirements offhand, but I'll admit I have no experience with such matters
either.

I imagine most compilers won't make use of this hint, but one way to
express it that is not compiler-specific is to cast the
pointer-to-void/char to a pointer-to-aligned-type. Even if the
resulting pointer is never used again, and its value is discarded, the
behaviour is undefined if the original pointer was not properly
aligned, so the compiler can assume it was. (Of course, even though
this is not compiler-specific, the actual alignment requirements of
almost all types are still system-specific.)
(I don't question that you can use assert() to portably convey
optimization hints, and it's actually a sensible application, if not what C
programs usually use it for.)

I do question it: when NDEBUG is defined, assertions may not have any
noticeable effect. Speficically, given a suitable definition of
is_aligned,

#define NDEBUG
#include <assert.h>
void mystrcat(char * restrict dst, const char * restrict src) {
assert( is_aligned(src) && is_aligned(dst) );
while( (*dst++ = *src++) != '\0' ) {}
}

must continue to work even if dst and src are not aligned.
 
S

Skarmander

Harald said:
I do question it: when NDEBUG is defined, assertions may not have any
noticeable effect.

Yes, you're right; you'd need an alternate version of assert() that ignores
NDEBUG (since such assertions are not for "debugging"). Losing performance
when NDEBUG is defined would be quite unintuitive.

S.
 
S

Szabolcs Borsanyi

Skarmander said:
Yes, you're right; you'd need an alternate version of assert() that ignores
NDEBUG (since such assertions are not for "debugging"). Losing performance when
NDEBUG is defined would be quite unintuitive.

Well, yes, but the code works correctly independet of NDEBUG, and NDEBUG
acts as an unintuitive optimizing flag.

Further, the optimization sensiteve code can be (and is in my case)
put into a separate file that may have an
#undef NDEBUG
right before
#include <assert.h>
If the file contains no other assertations (I use this macro mainly for giving
optimization hints) this does not result in problems.
But as I already wrote, I am not at all insisting that this is the best way
to give hints, to the compiler. By the way, I would prefer assertation
to casting: If (shame on me) there is a bug in my code, users (or me)
must withraw scientific papers..., an angry and unfriendly bug report is
still better. (My users don't care about the format of the message, just
that the program _must_be_bugfree_.)

Szabolcs Borsanyi
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,159
Messages
2,570,879
Members
47,416
Latest member
LionelQ387

Latest Threads

Top