checking constant conditions on compile time

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Urs Thuermann

    checking constant conditions on compile time

    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(st ruct foo) % 4 == 0);
    CHECK(sizeof(st ruct 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
  • Richard G. Riley

    #2
    Re: checking constant conditions on compile time

    On 2006-03-27, Urs Thuermann <urs@isnogud.es cape.de> wrote:[color=blue]
    > 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(st ruct foo) % 4 == 0);
    > CHECK(sizeof(st ruct 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[/color]

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



    or



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


    --
    Aspirat primo Fortuna labori.

    Comment

    • Eric Sosman

      #3
      Re: checking constant conditions on compile time

      Urs Thuermann wrote:
      [color=blue]
      > 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(st ruct foo) % 4 == 0);
      > CHECK(sizeof(st ruct 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.[/color]

      That's no problem as long as all the definitions
      agree.
      [color=blue]
      > 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?[/color]

      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
      esosman@acm-dot-org.invalid

      Comment

      • pete

        #4
        Re: checking constant conditions on compile time

        Urs Thuermann wrote:[color=blue]
        >
        > 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(st ruct foo) % 4 == 0);
        > CHECK(sizeof(st ruct 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?[/color]

        The assert macro in <assert.h>

        --
        pete

        Comment

        • pete

          #5
          Re: checking constant conditions on compile time

          pete wrote:[color=blue]
          >
          > Urs Thuermann wrote:[color=green]
          > >
          > > 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(st ruct foo) % 4 == 0);
          > > CHECK(sizeof(st ruct 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?[/color]
          >
          > The assert macro in <assert.h>[/color]

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

          --
          pete

          Comment

          • Jordan Abel

            #6
            Re: checking constant conditions on compile time

            On 2006-03-27, pete <pfilandr@minds pring.com> wrote:[color=blue]
            > Urs Thuermann wrote:[color=green]
            >>
            >> 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(st ruct foo) % 4 == 0);
            >> CHECK(sizeof(st ruct 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.[/color][/color]

            An array definition with size 0 is also a compile error. remove " - 1"
            from the definition. Also see below.
            [color=blue][color=green]
            >> 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?[/color]
            >
            > The assert macro in <assert.h>[/color]

            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.

            Comment

            • Chris Torek

              #7
              Re: checking constant conditions on compile time

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

              In article <slrne2ghv4.1jt f.random832@ran dom.yi.org>
              Jordan Abel <random832@gmai l.com> wrote:[color=blue]
              >An array definition with size 0 is also a compile error.[/color]

              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.)
              [color=blue]
              >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.[/color]

              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_FALS E_MINUS1(expr) ((((expr) != 0) * 2) - 1)
              #define COMPILE_TIME_AS SERT(expr) \
              (void)sizeof(ch ar [TRUE_PLUS1_FALS E_MINUS1(expr)])

              or similar.

              Note that both your CHECK and my COMPILE_TIME_AS SERT 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_AS SERT_WITH_NAME( expr, name) \
              typedef char name[TRUE_PLUS1_FALS E_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_EXPANSIO N(x, y) CONCAT(x, y)
              #define COMPILE_TIME_AS SERT_2(expr) \
              COMPILE_TIME_AS SERT_WITH_NAME( expr, CONCAT_EXPANSIO N(ASSERT, __LINE__))

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

              COMPILE_TIME_AS SERT_2(sizeof(i nt) == \
              sizeof(long)); COMPILE_TIME_AS SERT_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.

              Comment

              • Urs Thuermann

                #8
                Re: checking constant conditions on compile time

                Eric Sosman <esosman@acm-dot-org.invalid> writes:
                [color=blue]
                > 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])[/color]

                OK, but I prefer to do at file scope, i.e. outside of any block. The
                typedef suggested in this thread will do this.
                [color=blue]
                > I'd also suggest you arrange for the array size to be
                > negative rather than zero if the assertion fails.[/color]

                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.
                [color=blue]
                > 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?[/color]

                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

                Comment

                • Urs Thuermann

                  #9
                  Re: checking constant conditions on compile time

                  Chris Torek <nospam@torek.n et> writes:
                  [color=blue]
                  > #define COMPILE_TIME_AS SERT_WITH_NAME( expr, name) \
                  > typedef char name[TRUE_PLUS1_FALS E_MINUS1(expr)][/color]

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


                  urs

                  Comment

                  • Keith Thompson

                    #10
                    Re: checking constant conditions on compile time

                    Urs Thuermann <urs@isnogud.es cape.de> writes:
                    [...][color=blue]
                    > 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.[/color]
                    [...]

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

                    <http://groups.google.c om/group/comp.std.c/msg/4852afc61a060d8 9?hl=en&>

                    --
                    Keith Thompson (The_Other_Keit h) kst-u@mib.org <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.

                    Comment

                    • Ben Pfaff

                      #11
                      Re: checking constant conditions on compile time

                      Keith Thompson <kst-u@mib.org> writes:
                      [color=blue]
                      > What C compiler allowed sizeof to be evaluated in the preprocessor?[/color]

                      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.
                      [color=blue]
                      > <http://groups.google.c om/group/comp.std.c/msg/4852afc61a060d8 9?hl=en&>[/color]

                      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

                      Comment

                      • Keith Thompson

                        #12
                        Re: checking constant conditions on compile time

                        Ben Pfaff <blp@cs.stanfor d.edu> writes:[color=blue]
                        > Keith Thompson <kst-u@mib.org> writes:
                        >[color=green]
                        >> What C compiler allowed sizeof to be evaluated in the preprocessor?[/color]
                        >
                        > 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.
                        >[color=green]
                        >> <http://groups.google.c om/group/comp.std.c/msg/4852afc61a060d8 9?hl=en&>[/color]
                        >
                        > 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.[/color]

                        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_Keit h) kst-u@mib.org <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.

                        Comment

                        • Harald van Dijk

                          #13
                          Re: checking constant conditions on compile time

                          Keith Thompson wrote:[color=blue]
                          > Ben Pfaff <blp@cs.stanfor d.edu> writes:[color=green]
                          > > Keith Thompson <kst-u@mib.org> writes:
                          > >[color=darkred]
                          > >> What C compiler allowed sizeof to be evaluated in the preprocessor?[/color]
                          > >
                          > > 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.
                          > >[color=darkred]
                          > >> <http://groups.google.c om/group/comp.std.c/msg/4852afc61a060d8 9?hl=en&>[/color]
                          > >
                          > > 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.[/color]
                          >
                          > I'm wondering how it would even be possible. I suppose it could allow
                          > sizeof(type) only for the predefined types: int, float, etc.[/color]

                          This is what Decus CPP does. (Its last change was in 1985, apparently,
                          so it's understandable it doesn't support standard C.)
                          [color=blue]
                          > 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.[/color]

                          Indeed. It generates an error '#if sizeof, unknown type "struct"' here.
                          It doesn't even recognise the keyword.

                          Comment

                          • Ben Pfaff

                            #14
                            Re: checking constant conditions on compile time

                            Keith Thompson <kst-u@mib.org> writes:[color=blue]
                            > Ben Pfaff <blp@cs.stanfor d.edu> writes:[color=green]
                            >> Keith Thompson <kst-u@mib.org> writes:
                            >>[color=darkred]
                            >>> What C compiler allowed sizeof to be evaluated in the preprocessor?[/color]
                            >>
                            >> 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.[/color]
                            > 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.[/color]

                            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

                            Comment

                            • Urs Thuermann

                              #15
                              Re: checking constant conditions on compile time

                              Keith Thompson <kst-u@mib.org> writes:
                              [color=blue]
                              > What C compiler allowed sizeof to be evaluated in the preprocessor?
                              >
                              > <http://groups.google.c om/group/comp.std.c/msg/4852afc61a060d8 9?hl=en&>[/color]

                              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

                              Comment

                              Working...