www.panelsoft.com

 

 

 

Home

Training

Reading

PanelSoft

User Interfaces and Usability for Embedded Systems


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).

[PanelSoft Home | Training Courses ]