checking constant conditions on compile time

Discussion in 'C Programming' started by Urs Thuermann, Mar 27, 2006.

  1. What is the most elegant way to check certain conditions at compile
    time? I.e. I want a compile time error to be generated if for example
    the size of a struct is not a multiple of 4 or if one struct is larger
    than another struct, etc.

    I think of something like

    #define CHECK(expr) static int dummy[((expr) != 0) - 1]

    CHECK(sizeof(struct foo) % 4 == 0);
    CHECK(sizeof(struct foo) <= sizeof(struct bar));

    The macro expands to an array definition with size -1 which causes a
    compile error, if the expr is false, i.e. zero.

    The unpleasant thing in this definition is that it pollutes the names
    space with a file scope name and I can use it only once per file,
    since otherwise the array is defined multiply. Second, using the
    preprocessor #error with an appropriate message would be nicer, but
    the preprocessor #if can't be used, since the preprocessor can't
    evaluate the sizeof operator.

    So, is there some other nice way to achieve what I am looking for?

    urs
    Urs Thuermann, Mar 27, 2006
    #1
    1. Advertising

  2. On 2006-03-27, Urs Thuermann <> wrote:
    > What is the most elegant way to check certain conditions at compile
    > time? I.e. I want a compile time error to be generated if for example
    > the size of a struct is not a multiple of 4 or if one struct is larger
    > than another struct, etc.
    >
    > I think of something like
    >
    > #define CHECK(expr) static int dummy[((expr) != 0) - 1]
    >
    > CHECK(sizeof(struct foo) % 4 == 0);
    > CHECK(sizeof(struct foo) <= sizeof(struct bar));
    >
    > The macro expands to an array definition with size -1 which causes a
    > compile error, if the expr is false, i.e. zero.
    >
    > The unpleasant thing in this definition is that it pollutes the names
    > space with a file scope name and I can use it only once per file,
    > since otherwise the array is defined multiply. Second, using the
    > preprocessor #error with an appropriate message would be nicer, but
    > the preprocessor #if can't be used, since the preprocessor can't
    > evaluate the sizeof operator.
    >
    > So, is there some other nice way to achieve what I am looking for?
    >
    > urs


    I had a quick google up of this since I was wondering about something
    to do with sizeof anyway : this thread might help you --

    http://tinyurl.com/ktbnh

    or

    http://groups.google.de/groups?q=ccassert

    and the thread entitled "How two check struct size at compile time"


    --
    Aspirat primo Fortuna labori.
    Richard G. Riley, Mar 27, 2006
    #2
    1. Advertising

  3. Urs Thuermann

    Eric Sosman Guest

    Urs Thuermann wrote:

    > What is the most elegant way to check certain conditions at compile
    > time? I.e. I want a compile time error to be generated if for example
    > the size of a struct is not a multiple of 4 or if one struct is larger
    > than another struct, etc.
    >
    > I think of something like
    >
    > #define CHECK(expr) static int dummy[((expr) != 0) - 1]
    >
    > CHECK(sizeof(struct foo) % 4 == 0);
    > CHECK(sizeof(struct foo) <= sizeof(struct bar));
    >
    > The macro expands to an array definition with size -1 which causes a
    > compile error, if the expr is false, i.e. zero.
    >
    > The unpleasant thing in this definition is that it pollutes the names
    > space with a file scope name and I can use it only once per file,
    > since otherwise the array is defined multiply.


    That's no problem as long as all the definitions
    agree.

    > Second, using the
    > preprocessor #error with an appropriate message would be nicer, but
    > the preprocessor #if can't be used, since the preprocessor can't
    > evaluate the sizeof operator.
    >
    > So, is there some other nice way to achieve what I am looking for?


    Perhaps you could exploit the `sizeof' operator to
    provoke the same error without actually declaring a data
    object. Off-hand I can't think of a way to do this at
    file scope (I can't think of a way to write a declaration
    or definition that's a no-op), but if CHECK is used inside
    function blocks it can expand to an executable no-op, e.g.

    #define CHECK(expr) sizeof(char[((expr) != 0) - 1])

    I'd also suggest you arrange for the array size to be
    negative rather than zero if the assertion fails. Some
    compilers support "C-ish" modes that permit zero-length
    arrays, and you'd like CHECK to fail even if the compiler
    is being operated in such a mode.

    However, my larger suggestion is that you take a step
    back and reconsider why you need CHECK in the first place.
    Both the examples you give (perhaps not coincidentally) give
    evidence of dubious design and coding practices. Why do you
    care whether sizeof(struct foo) is a multiple of four? Why
    would sizeof(struct foo) > sizeof(struct bar) make trouble
    for your program? If you're concerned about such things, it
    seems likely that you're engaging in type-punning or that
    you're trying to match externally-imposed formats. In either
    case, it might be better to re-code in cleaner fashion than
    to ask the compiler for an "all clear" on dodgy doings.

    Long ago I was a fan of strewing the code with compiler
    bombs. I used them to check conditions somewhat like those
    you illustrate, and I used them to mark temporary hacks that
    needed to be revisited before product release. (This was
    after I tracked a performance bug down to a "temporary" hack
    that had lain forgotten in the code through three releases...)
    Eventually, though, I came to believe that the compiler is a
    translator, not an enforcer of software engineering standards.

    --
    Eric Sosman
    lid
    Eric Sosman, Mar 27, 2006
    #3
  4. Urs Thuermann

    pete Guest

    Urs Thuermann wrote:
    >
    > What is the most elegant way to check certain conditions at compile
    > time? I.e. I want a compile time error to be generated if for example
    > the size of a struct is not a multiple of 4 or if one struct is larger
    > than another struct, etc.
    >
    > I think of something like
    >
    > #define CHECK(expr) static int dummy[((expr) != 0) - 1]
    >
    > CHECK(sizeof(struct foo) % 4 == 0);
    > CHECK(sizeof(struct foo) <= sizeof(struct bar));
    >
    > The macro expands to an array definition with size -1 which causes a
    > compile error, if the expr is false, i.e. zero.
    >
    > The unpleasant thing in this definition is that it pollutes the names
    > space with a file scope name and I can use it only once per file,
    > since otherwise the array is defined multiply. Second, using the
    > preprocessor #error with an appropriate message would be nicer, but
    > the preprocessor #if can't be used, since the preprocessor can't
    > evaluate the sizeof operator.
    >
    > So, is there some other nice way to achieve what I am looking for?


    The assert macro in <assert.h>

    --
    pete
    pete, Mar 27, 2006
    #4
  5. Urs Thuermann

    pete Guest

    pete wrote:
    >
    > Urs Thuermann wrote:
    > >
    > > What is the most elegant way to check certain conditions at compile
    > > time? I.e. I want a compile time error to be generated if for example
    > > the size of a struct is not a multiple of 4 or if one struct is larger
    > > than another struct, etc.
    > >
    > > I think of something like
    > >
    > > #define CHECK(expr) static int dummy[((expr) != 0) - 1]
    > >
    > > CHECK(sizeof(struct foo) % 4 == 0);
    > > CHECK(sizeof(struct foo) <= sizeof(struct bar));
    > >
    > > The macro expands to an array definition with size -1 which causes a
    > > compile error, if the expr is false, i.e. zero.
    > >
    > > The unpleasant thing in this definition is that it pollutes the names
    > > space with a file scope name and I can use it only once per file,
    > > since otherwise the array is defined multiply. Second, using the
    > > preprocessor #error with an appropriate message would be nicer, but
    > > the preprocessor #if can't be used, since the preprocessor can't
    > > evaluate the sizeof operator.
    > >
    > > So, is there some other nice way to achieve what I am looking for?

    >
    > The assert macro in <assert.h>


    Actually, that's for run time not compile time.

    --
    pete
    pete, Mar 27, 2006
    #5
  6. Urs Thuermann

    Jordan Abel Guest

    On 2006-03-27, pete <> wrote:
    > Urs Thuermann wrote:
    >>
    >> What is the most elegant way to check certain conditions at compile
    >> time? I.e. I want a compile time error to be generated if for example
    >> the size of a struct is not a multiple of 4 or if one struct is larger
    >> than another struct, etc.
    >>
    >> I think of something like
    >>
    >> #define CHECK(expr) static int dummy[((expr) != 0) - 1]
    >>
    >> CHECK(sizeof(struct foo) % 4 == 0);
    >> CHECK(sizeof(struct foo) <= sizeof(struct bar));
    >>
    >> The macro expands to an array definition with size -1 which causes a
    >> compile error, if the expr is false, i.e. zero.


    An array definition with size 0 is also a compile error. remove " - 1"
    from the definition. Also see below.

    >> The unpleasant thing in this definition is that it pollutes the names
    >> space with a file scope name and I can use it only once per file,
    >> since otherwise the array is defined multiply. Second, using the
    >> preprocessor #error with an appropriate message would be nicer, but
    >> the preprocessor #if can't be used, since the preprocessor can't
    >> evaluate the sizeof operator.
    >>
    >> So, is there some other nice way to achieve what I am looking for?

    >
    > The assert macro in <assert.h>


    That's a run-time assert. He wants to check properties of constant
    expressions at compile-time. I believe what he came up with is similar
    to the traditional solution, other than the fact that it doesn't work
    (for the reason I pointed out)

    How about
    #define CHECK(expr) (void)((int(*)[(expr)!=0])0)
    cast /* null pointer constant */ 0 into pointer to array (expr)!=0 of
    int, then cast to void, discarding.
    Jordan Abel, Mar 27, 2006
    #6
  7. Urs Thuermann

    Chris Torek Guest

    [On building a "compile-time assert" macro]

    In article <>
    Jordan Abel <> wrote:
    >An array definition with size 0 is also a compile error.


    It is in Standard C. Unfortunately, GNUC is quite popular, and
    arrays with size zero are fine in GNUC, so in practice one must
    often come up with a trick that works in both Standard C *and* GNUC.
    (Zero-size arrays are probably available in some other not-quite-C
    languages as well.)

    >How about
    >#define CHECK(expr) (void)((int(*)[(expr)!=0])0)
    >cast /* null pointer constant */ 0 into pointer to array (expr)!=0 of
    >int, then cast to void, discarding.


    The (expr)!=0 part converts to 0 (if expr is false) or 1 (if expr
    is true), which works fine for Standard C (as noted above). To
    make it work for both Standard C and not-quite-C, we can convert
    1 to 1 and 0 to -1:

    #define TRUE_PLUS1_FALSE_MINUS1(expr) ((((expr) != 0) * 2) - 1)
    #define COMPILE_TIME_ASSERT(expr) \
    (void)sizeof(char [TRUE_PLUS1_FALSE_MINUS1(expr)])

    or similar.

    Note that both your CHECK and my COMPILE_TIME_ASSERT have to
    be put in the "code" part of a program (inside a block, and
    after the declarations in C89). There is a variant that can
    appear only where declarations can go:

    #define COMPILE_TIME_ASSERT_WITH_NAME(expr, name) \
    typedef char name[TRUE_PLUS1_FALSE_MINUS1(expr)]

    which is probably most useful with a few auxiliary macros to
    generate an assertion-name based on source line number:

    #define CONCAT(x, y) x ## y
    #define CONCAT_EXPANSION(x, y) CONCAT(x, y)
    #define COMPILE_TIME_ASSERT_2(expr) \
    COMPILE_TIME_ASSERT_WITH_NAME(expr, CONCAT_EXPANSION(ASSERT, __LINE__))

    Of course, you can only put one COMPILE_TIME_ASSERT_2() invocation
    on any logical source line ("logical" meaning "after physical lines
    are joined via backslash-newline splicing"). Thus:

    COMPILE_TIME_ASSERT_2(sizeof(int) == \
    sizeof(long)); COMPILE_TIME_ASSERT_2(CHAR_MAX == 127);

    is bad for several reasons. :)
    --
    In-Real-Life: Chris Torek, Wind River Systems
    Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
    email: forget about it http://web.torek.net/torek/index.html
    Reading email is like searching for food in the garbage, thanks to spammers.
    Chris Torek, Mar 28, 2006
    #7
  8. Eric Sosman <> writes:

    > but if CHECK is used inside
    > function blocks it can expand to an executable no-op, e.g.
    >
    > #define CHECK(expr) sizeof(char[((expr) != 0) - 1])


    OK, but I prefer to do at file scope, i.e. outside of any block. The
    typedef suggested in this thread will do this.

    > I'd also suggest you arrange for the array size to be
    > negative rather than zero if the assertion fails.


    I have actually written the macro so it makes the array size negative
    if the assertion fails. But I should you positive instead of null
    value, when the assertion holds, since [0] seems to be invalid, too.
    I thought, it is allowed.

    > However, my larger suggestion is that you take a step
    > back and reconsider why you need CHECK in the first place.
    > Both the examples you give (perhaps not coincidentally) give
    > evidence of dubious design and coding practices. Why do you
    > care whether sizeof(struct foo) is a multiple of four? Why
    > would sizeof(struct foo) > sizeof(struct bar) make trouble
    > for your program?


    The check for multiple of 4 is something I needed 10+ years ago. I
    memcpy()ed the struct to some memory block which was the input to a
    compression algortihm that operated on 4-byte-values. I could do it
    then, because the use compiler allowed siyeof() to be evaluated in the
    C preprocessor. Today I would probably doit it in another way.

    The other example comes from implementation of a new communication
    protocol family, where I use a struct defined in some existing source
    code I cannot change. The struct contains a union to hold data for a
    number of already implemented protocols. My new protocol should use
    the space of this union, too, but I ust ensure, that the struct for my
    new protocol is not larger than the union.

    urs
    Urs Thuermann, Mar 30, 2006
    #8
  9. Chris Torek <> writes:

    > #define COMPILE_TIME_ASSERT_WITH_NAME(expr, name) \
    > typedef char name[TRUE_PLUS1_FALSE_MINUS1(expr)]


    Ah, the typedef is also nice, so not to create unused objects. Thanks
    to all who have answered, to refine my first approach.


    urs
    Urs Thuermann, Mar 30, 2006
    #9
  10. Urs Thuermann <> writes:
    [...]
    > The check for multiple of 4 is something I needed 10+ years ago. I
    > memcpy()ed the struct to some memory block which was the input to a
    > compression algortihm that operated on 4-byte-values. I could do it
    > then, because the use compiler allowed siyeof() to be evaluated in the
    > C preprocessor. Today I would probably doit it in another way.

    [...]

    What C compiler allowed sizeof to be evaluated in the preprocessor?

    <http://groups.google.com/group/comp.std.c/msg/4852afc61a060d89?hl=en&>

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
    Keith Thompson, Mar 31, 2006
    #10
  11. Urs Thuermann

    Ben Pfaff Guest

    Keith Thompson <> writes:

    > What C compiler allowed sizeof to be evaluated in the preprocessor?


    I seem to recall that at least some versions of the C compiler
    included with Turbo C++ for DOS did so. But I suppose this could
    just be bad memory.

    > <http://groups.google.com/group/comp.std.c/msg/4852afc61a060d89?hl=en&>


    Ritchie's response is humorous, for sure, but it has little to do
    with the question of whether any C compiler has allowed sizeof in
    the preprocessor.
    --
    "If I've told you once, I've told you LLONG_MAX times not to
    exaggerate."
    --Jack Klein
    Ben Pfaff, Mar 31, 2006
    #11
  12. Ben Pfaff <> writes:
    > Keith Thompson <> writes:
    >
    >> What C compiler allowed sizeof to be evaluated in the preprocessor?

    >
    > I seem to recall that at least some versions of the C compiler
    > included with Turbo C++ for DOS did so. But I suppose this could
    > just be bad memory.
    >
    >> <http://groups.google.com/group/comp.std.c/msg/4852afc61a060d89?hl=en&>

    >
    > Ritchie's response is humorous, for sure, but it has little to do
    > with the question of whether any C compiler has allowed sizeof in
    > the preprocessor.


    I'm wondering how it would even be possible. I suppose it could allow
    sizeof(type) only for the predefined types: int, float, etc.
    Supporting it in general:

    struct foo {
    int x;
    char y;
    }

    #if sizeof(struct foo) == 8

    would require the preprocessor to be able to parse C declarations.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
    Keith Thompson, Mar 31, 2006
    #12
  13. Keith Thompson wrote:
    > Ben Pfaff <> writes:
    > > Keith Thompson <> writes:
    > >
    > >> What C compiler allowed sizeof to be evaluated in the preprocessor?

    > >
    > > I seem to recall that at least some versions of the C compiler
    > > included with Turbo C++ for DOS did so. But I suppose this could
    > > just be bad memory.
    > >
    > >> <http://groups.google.com/group/comp.std.c/msg/4852afc61a060d89?hl=en&>

    > >
    > > Ritchie's response is humorous, for sure, but it has little to do
    > > with the question of whether any C compiler has allowed sizeof in
    > > the preprocessor.

    >
    > I'm wondering how it would even be possible. I suppose it could allow
    > sizeof(type) only for the predefined types: int, float, etc.


    This is what Decus CPP does. (Its last change was in 1985, apparently,
    so it's understandable it doesn't support standard C.)

    > Supporting it in general:
    >
    > struct foo {
    > int x;
    > char y;
    > }
    >
    > #if sizeof(struct foo) == 8
    >
    > would require the preprocessor to be able to parse C declarations.


    Indeed. It generates an error '#if sizeof, unknown type "struct"' here.
    It doesn't even recognise the keyword.
    =?utf-8?B?SGFyYWxkIHZhbiBExLNr?=, Mar 31, 2006
    #13
  14. Urs Thuermann

    Ben Pfaff Guest

    Keith Thompson <> writes:
    > Ben Pfaff <> writes:
    >> Keith Thompson <> writes:
    >>
    >>> What C compiler allowed sizeof to be evaluated in the preprocessor?

    >>
    >> I seem to recall that at least some versions of the C compiler
    >> included with Turbo C++ for DOS did so. But I suppose this could
    >> just be bad memory.

    > I'm wondering how it would even be possible. I suppose it could allow
    > sizeof(type) only for the predefined types: int, float, etc.
    > Supporting it in general:
    >
    > struct foo {
    > int x;
    > char y;
    > }
    >
    > #if sizeof(struct foo) == 8
    >
    > would require the preprocessor to be able to parse C declarations.


    Is it really so mysterious? The preprocessor and compiler were
    integrated into a single pass, and a single process, in that
    compiler. Thus, the preprocessor had access to the symbol table.
    That's the way I remember it working, anyhow.
    --
    "The expression isn't unclear *at all* and only an expert could actually
    have doubts about it"
    --Dan Pop
    Ben Pfaff, Mar 31, 2006
    #14
  15. Keith Thompson <> writes:

    > What C compiler allowed sizeof to be evaluated in the preprocessor?
    >
    > <http://groups.google.com/group/comp.std.c/msg/4852afc61a060d89?hl=en&>


    Turbo C and Pure C for the Atari ST from Application System
    Heidelberg. That was around 1992/1993 that I used it.

    Compiler and preprocessor were tightly integrated, as others already
    mentioned for other compilers, so the preprocessor was able to
    evaluate the sizeof operator.

    urs
    Urs Thuermann, Mar 31, 2006
    #15
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    1
    Views:
    563
    Chris Uppal
    Nov 17, 2005
  2. Lionel B
    Replies:
    6
    Views:
    9,528
    Alf P. Steinbach
    May 14, 2004
  3. Nagaraj
    Replies:
    1
    Views:
    837
    Lionel B
    Mar 1, 2007
  4. Carter
    Replies:
    2
    Views:
    490
    Carter
    Mar 4, 2009
  5. Wilson Bilkovich
    Replies:
    0
    Views:
    85
    Wilson Bilkovich
    Nov 8, 2005
Loading...

Share This Page