Feedback to Assertiveness Training for Programmers - Murphy's
Law, Apr' 2001
return to Murphy's Law
Errata
This column has a mistake in the first example in the Size
Matters section. The example is:
assert (sizeof(struct myData) > SIZE);
It should read:
assert (sizeof(struct myData) <= SIZE);
My thanks to Scott Newell for pointing this out to me.
Feedback
Bill Emsholl mailed
me with a method for doing compile time asserts without using
a single byte of ROM or RAM - something I narrowly failed to do
in the column itself. His useful mail follows:
Thanks for writing
a column on the use of assert(). I too, have also found that this
macro is still not widely used, and is often misused.
However, I would like
to offer a better compile-time assert macro than the use of a
static variable as illustrated in the article. Besides the fact
that many compilers recognize a zero-sized array as valid, most
compilers will also produce a spurious warning on unused variables.
These problems can
be solved through the use of a typedef to an array whose dimensions
are positive or negative depending on the expression, as below:
/* macro to test an expression at compile time.
produces a compiler error if invalid; produces no code if valid.
The expression is in braces to allow it to be used multiple times
in the same block.
*/
#define CASSERT(ex) { typedef char cassert_type[(ex) ? 1 : -1]; }
void foo(void) {
CASSERT(sizeof(char) >= 1);
CASSERT(sizeof(int) >= 2);
}
void bar(void) {
CASSERT(sizeof(char) >= 2); // compile-time error
}
The above macro was
tested on 3 different C/C++ compilers, and a typedef doesn't even
occupy a single byte of storage...
Keep up the good work,
Bill Bill Emshoff
Lockheed Martin Aeronautics
Well I thought I couldn't
be the first to discover this one, and I see I'm not. I have just
found a variant of this at... http://www.panelsoft.com/murphyslaw/apr01.htm
This is a definite
improvement since it uses a harmless typedef instead.
However, Bill Emsholl's
variant doesn't swallow the semicolon and it cannot be used outside
a function (at file scope).
So here is my new
variant....
#define COMPILE_TIME_ASSERT(ex) do {\
typedef char COMPILE_TIME_ASSERTION_FAILURE[(ex) ? 1 : -1];\
} while(0)
#define FILE_SCOPED_COMPILE_TIME_ASSERT(ex) \
extern char COMPILE_TIME_ASSERTION_FAILURE[(ex) ? 1 : -1];
FILE_SCOPED_COMPILE_TIME_ASSERT(sizeof(int)==4);
FILE_SCOPED_COMPILE_TIME_ASSERT(sizeof(char)==2); // Compiler whinges
int main(void)
{
COMPILE_TIME_ASSERT(sizeof(int)==4);
if(1)
COMPILE_TIME_ASSERT(1);
else
printf("Foo\n");
if(0)
COMPILE_TIME_ASSERT(0); // Compiler whinges.
else
printf("Foo\n");
return 0;
}
John Carter
Tait Electronics
Christchurch
New Zealand
Another vote for
the healing powers of assert macros:
Hi,
I just read your article
on the Assert() macro. Like you I've been astounded at the number
of "professional" software engineers who've never heard of it.
I learnt about it from McQuire's book about a year ago, and have
since liberally sprinkled assertions throught my embedded code
during development. It very quickly shows up serious program flow
errors, which are the bugs that usually slip through.
The article was very
good.
Regards
Phil Matthews
Hi Niall,
I like the trick you give
to validate the size of a structure. I'm using it to validate at
compilation that the size of our global structures match the documentation.
I ran into a problem with our tool vendor's C/CPP compiler. It will
allocate an array of 0 bytes. The compiler doesn't give you an error
until you attempt to access the zero length array!
Bob
Robert E. Lee
Firmware Engineer
GE Meter Business Department
Niall's Response:
I have to admit I have
gone off this trick for a while. I (and others) have discovered
that compilers are not strict enough in this area, so you can never
be sure if it is going to work - regardless of what the C standard
says. My compromise is to use an assert, which has a small cost
in space, and the error is only reported at run-time, but at least
the run-time assert is traced back to the exact cause of the failure
(unlike accessing out of bounds areas, which can be hard to debug). |