🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: comp.lang.c.moderated
6 messages
6 total messages Started by Mike Haertel Mon, 01 Apr 1996 13:19
Interesting compile-time assertion macro
#2444
Author: Mike Haertel
Date: Mon, 01 Apr 1996 13:19
46 lines
2057 bytes
Lately I have been writing a device driver for a gadget
with some shared-memory data structures.  In the course
of doing this I've needed to satisfy certain constraints
on staticly allocated sizes and alignments of data
structures.  I hate it when things blow up at run time
that could obviously be avoided at compile time.

So I came up with a compile-time equivalent of <assert.h>:

/*
 * Cause a compile-time error if the asserted expression, which
 * must be a constant expression according to the rules of ANSI C,
 * is false.  Each use of this macro must supply a different
 * identifier for KEY.
 *
 * It works by trying to declare an array of negative size if
 * the asserted expression is false.
 */
#define ASSERT_COMPILE_TIME(EXPR, KEY)                                  \
        struct ASSERT_COMPILE_TIME_##KEY {                              \
                char ASSERT_COMPILE_TIME_##KEY[2*((EXPR) != 0) - 1];    \
        }

Then you can do things like:

struct foo {
	int x;
	int y;
};

ASSERT_COMPILE_TIME(offsetof(struct foo, y) == 4,
	y_is_at_offset_4);

I've found this to be quite useful for error checking in a
complex piece of code which is parameterized by several
#defines, which must together satisfy various constraints.
It's much easier than saying "Warning: FOO*7 + BAR*3 must be
less than 50 or this will not work" in a comment, and gives a
bit of confidence that it would be hard for someone else to
mess up the code accidently.

Anyway, I'm curious.  Has anyone ever seen this particular
hack before?
--
Mike Haertel <haertel@ichips.intel.com>
Not speaking for Intel.
Re: Interesting compile-time assertion macro
#2453
Author: Raymond Chen
Date: Tue, 02 Apr 1996 01:54
11 lines
898 bytes
On 1 Apr 1996 07:19:33 -0600, haertel@ichips.intel.com (Mike Haertel)
wrote:
>Has anyone ever seen this particular hack before?

Not that particular hack, but I've used this one:

#define AssertNow(c) switch (c) case 0: case c:

The trailing semicolon terminates the switch() statement.  (As
written, it's designed to be used inside a function.  Adjusting it to
work outside a function is left as an exercise.)
Re: Interesting compile-time assertion macro
#2460
Author: Mike Coffman
Date: Tue, 02 Apr 1996 01:59
52 lines
2559 bytes
Mike Haertel wrote in comp.lang.c.moderated:
> So I came up with a compile-time equivalent of <assert.h>:
> 
> /*
>  * Cause a compile-time error if the asserted expression, which
>  * must be a constant expression according to the rules of ANSI C,
>  * is false.  Each use of this macro must supply a different
>  * identifier for KEY.
>  *
>  * It works by trying to declare an array of negative size if
>  * the asserted expression is false.
>  */
> #define ASSERT_COMPILE_TIME(EXPR, KEY)                                  \
>         struct ASSERT_COMPILE_TIME_##KEY {                              \
>                 char ASSERT_COMPILE_TIME_##KEY[2*((EXPR) != 0) - 1];    \
>         }

Mike:
I like the principle of protecting the users of source code that I write 
from the mistakes they make adjusting the parameters to their
application.
I usually use the sequence:
 
#if test_condition
#error error message
#endif 

but, as you can see, this takes three lines to invoke to your one.

The only overhead/disadvantage to your technique is that once I get my
code to compile successfully I have a number of structures composed of
one element character arrays taking up a little space.

My editorial comment: 
This is one more instance where the implementation of the C preprocessor 
has caused additional work or inconvenience.  If a #define could be 
defined to contain additional preprocessing directives, my #if, #error, 
#endif sequence could be defined as a macro, and invoked as easily as 
Mike's ASSERT_COMPILE_ASSERT(EXPR, KEY) macro.  

The improvement would be a more obvious macro (test a condition and 
produce and error message) rather than relying on Mike's clever but
mildly 
obscure technique of conditionally producing an error message by 
defining an array with a negative dimension, which also has the slight
side effect of using a small amount of storage for each successful
compile
time assert macro.

Mike Coffman 
coffman@cat.com
*** My opinions only and not necessarily those of my employer. ***
Re: Interesting compile-time assertion macro
#2482
Author: Thad Smith
Date: Wed, 03 Apr 1996 13:12
60 lines
2935 bytes
In article <4jq1lg$a67@solutions.solon.com>,
Mike Coffman <coffman@cat.com> wrote:
>Mike Haertel wrote in comp.lang.c.moderated:
>> So I came up with a compile-time equivalent of <assert.h>:
>> 
>> /*
>>  * Cause a compile-time error if the asserted expression, which
>>  * must be a constant expression according to the rules of ANSI C,
>>  * is false.  Each use of this macro must supply a different
>>  * identifier for KEY.
>>  *
>>  * It works by trying to declare an array of negative size if
>>  * the asserted expression is false.
>>  */
>> #define ASSERT_COMPILE_TIME(EXPR, KEY)                                  \
>>         struct ASSERT_COMPILE_TIME_##KEY {                              \
>>                 char ASSERT_COMPILE_TIME_##KEY[2*((EXPR) != 0) - 1];    \
>>         }
>
>Mike:
>I like the principle of protecting the users of source code that I write 
>from the mistakes they make adjusting the parameters to their
>application.
>I usually use the sequence:
> 
>#if test_condition
>#error error message
>#endif 
>
>but, as you can see, this takes three lines to invoke to your one.

The other problem is that the preprocessor doesn't have access to the
full power of constant expressions invoving sizeof, offsetof, etc.

I found Mike Haertel's macro clever and inspiring.  I suggested in
email that the struct name could be omitted, so that the KEY
parameter isn't required.  He responded that the gcc produced a
warning for such a declaration.  I have put together a version which
concatenates __LINE__ to a symbol to make it unique:

 /* ASSERT_COMPILE_TIME() allows a constant expression to be evaluated
 ** at compile time.  It causes an error, due to negative array size,
 ** if the expression is false.  It must be placed where declarations
 ** are allowed.
 ** Adapted from posting 1 Apr 1996 in comp.lang.c.moderated by
 ** haertel@ichips.intel.com (Mike Haertel).
 */
 #define ASSERT_CAT1(x) ASSERT_CAT ## x
 #define ASSERT_CAT0(x) ASSERT_CAT1(x)
 #define ASSERT_COMPILE_TIME(expr)  \
         struct ASSERT_CAT0(__LINE__){char t[2*!!(expr)-1];}

>The only overhead/disadvantage to your technique is that once I get my
>code to compile successfully I have a number of structures composed of
>one element character arrays taking up a little space.

Not really.  A struct is defined, but not declared, i.e., there is no
struct variable so no space is taken.  :-)

Thad
Re: Interesting compile-time assertion macro
#2492
Author: Henning Makholm
Date: Thu, 04 Apr 1996 01:09
24 lines
1251 bytes
Mike Coffman <coffman@cat.com> writes:

>Mike Haertel wrote in comp.lang.c.moderated:

>> #define ASSERT_COMPILE_TIME(EXPR, KEY)                                  \
>>         struct ASSERT_COMPILE_TIME_##KEY {                              \
>>                 char ASSERT_COMPILE_TIME_##KEY[2*((EXPR) != 0) - 1];    \
>>         }

>I usually use the sequence:
> 
>#if test_condition
>#error error message
>#endif 
>
>but, as you can see, this takes three lines to invoke to your one.

And, additionally, Mike H.'s macro accepts expressions involving
sizeof, which #if knows nothing about.

-- 

Henning Makholm - math and CS student - University of Copenhagen
makholm@diku.dk - http://www.diku.dk/students/makholm - fido 2:235/224.92
Re: Interesting compile-time assertion macro
#2494
Author: Konrad Schwarz
Date: Thu, 04 Apr 1996 01:10
13 lines
887 bytes
In article <4jq1lg$a67@solutions.solon.com>, Mike Coffman <coffman@cat.com> writes:

|> #if test_condition
|> #error error message
|> #endif 

|> The only overhead/disadvantage to your technique is that once I get my
|> code to compile successfully I have a number of structures composed of
|> one element character arrays taking up a little space.

You're forgetting sizeof expressions.

Konrad Schwarz
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads