Werid <sys/queue.h> - it has useless do{} while(0) - Unix

This is a discussion on Werid <sys/queue.h> - it has useless do{} while(0) - Unix ; (Since queue.h is not a part of standard C, I'd lke to ask here) For example, BSD implementation of sys/queue.h has following weird macros: I can't understand why "do{}while(0)" is used... Removing "do{}while(0)" from these macros should be ok. Right? ...

+ Reply to Thread
Results 1 to 7 of 7

Thread: Werid <sys/queue.h> - it has useless do{} while(0)

  1. Werid <sys/queue.h> - it has useless do{} while(0)

    (Since queue.h is not a part of standard C, I'd lke to ask here)

    For example, BSD implementation of sys/queue.h has following weird
    macros:
    I can't understand why "do{}while(0)" is used... Removing
    "do{}while(0)" from these macros should be ok. Right?


    #define SLIST_INIT(head) do { \
    SLIST_FIRST((head)) = NULL; \
    } while (0)

    #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
    SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
    SLIST_NEXT((slistelm), field) = (elm); \
    } while (0)

    #define SLIST_INSERT_HEAD(head, elm, field) do { \
    SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
    SLIST_FIRST((head)) = (elm); \
    } while (0)

    #define SLIST_NEXT(elm, field) ((elm)->field.sle_next)


  2. Re: Werid <sys/queue.h> - it has useless do{} while(0)

    djhong@gmail.com wrote On 04/26/07 13:47,:
    > (Since queue.h is not a part of standard C, I'd lke to ask here)
    >
    > For example, BSD implementation of sys/queue.h has following weird
    > macros:
    > I can't understand why "do{}while(0)" is used... Removing
    > "do{}while(0)" from these macros should be ok. Right?
    >
    >
    > #define SLIST_INIT(head) do { \
    > SLIST_FIRST((head)) = NULL; \
    > } while (0)
    >
    > #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
    > SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
    > SLIST_NEXT((slistelm), field) = (elm); \
    > } while (0)
    >
    > #define SLIST_INSERT_HEAD(head, elm, field) do { \
    > SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
    > SLIST_FIRST((head)) = (elm); \
    > } while (0)
    >
    > #define SLIST_NEXT(elm, field) ((elm)->field.sle_next)


    (You seem to be missing some backslashes.)

    No reason I can see for do{}while(0) on the first
    one, but for the next two it makes sense. Maybe the
    first has do{}while(0) just for consistency's sake, or
    maybe an earlier version of the first macro had more
    than one statement.

    The reason for the do{}while(0) dodge in multi-
    statement macro expansions is to make them work right
    in contexts where just one statement is allowed. For
    example, try this simple macro:

    #define MESSAGE(msg) { \
    fputs (msg, stdout);
    fputs (msg, stderr);
    }

    Easy enough, right? MESSAGE("Hello, world!\n") writes
    the message to two output streams. But let's try it
    in this context:

    if (firstGreetingOfTheDay)
    MESSAGE("Hello, world!\n");
    else
    MESSAGE("Hi again.\n");

    (If you don't see the problem, feed it to a compiler
    and see what it says.)

    Now, you could "fix" this with documentation: "When
    you use the MESSAGE macro, never put a semicolon at
    the end." But that's not a really wonderful solution
    because it requires the programmer to be aware that this
    "function-like macro" is really a macro and not an actual
    function, and requires that it be coded with a different
    style than pretty much everything else. (And it will
    probably raise merry Hell with automatic code formatters,
    too.) The do{}while(0) dodge turns the macro expansion
    into a single semicolon-terminated statement, and the
    programmer's life gets simpler.

    --
    Eric.Sosman@sun.com

  3. Re: Werid <sys/queue.h> - it has useless do{} while(0)

    djhong@gmail.com writes:

    >(Since queue.h is not a part of standard C, I'd lke to ask here)


    >For example, BSD implementation of sys/queue.h has following weird
    >macros:
    >I can't understand why "do{}while(0)" is used... Removing
    >"do{}while(0)" from these macros should be ok. Right?



    >#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
    > SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
    > SLIST_NEXT((slistelm), field) = (elm); \
    >} while (0)




    Wrong!
    Consider the preprocessor's textual expansion of:

    if(condition)
    SLIST_INSERT_AFTER(myslistelm, myelm, myfield);
    else
    statement2;

    If any *do* turn out to be redundant (the first one is I think),
    let the compiler/optimizer do it.

    --
    Chris.

  4. Re: Werid <sys/queue.h> - it has useless do{} while(0)

    Eric Sosman wrote On 04/26/07 14:34,:
    > djhong@gmail.com wrote On 04/26/07 13:47,:
    >> [...]
    >>
    >>#define SLIST_INIT(head) do { \
    >> SLIST_FIRST((head)) = NULL; \
    >>} while (0)
    >>

    > [...]
    >
    > (You seem to be missing some backslashes.)


    Woops! You're not missing backslashes; I was
    using too narrow a window. Sorry about that.

    --
    Eric.Sosman@sun.com

  5. Re: Werid <sys/queue.h> - it has useless do{} while(0)

    "Eric Sosman" wrote in message
    news:1177612444.288279@news1nwk...
    > djhong@gmail.com wrote On 04/26/07 13:47,:
    > > (Since queue.h is not a part of standard C, I'd lke to ask here)
    > >
    > > For example, BSD implementation of sys/queue.h has following weird
    > > macros:
    > > I can't understand why "do{}while(0)" is used... Removing
    > > "do{}while(0)" from these macros should be ok. Right?

    >
    > The reason for the do{}while(0) dodge in multi-
    > statement macro expansions is to make them work right
    > in contexts where just one statement is allowed.


    At the expense of contexts where no statements are allowed -- only
    expressions.

    karl m



  6. Re: Werid <sys/queue.h> - it has useless do{} while(0)

    karl malbrain wrote On 04/26/07 15:19,:
    > "Eric Sosman" wrote in message
    > news:1177612444.288279@news1nwk...
    >
    >>djhong@gmail.com wrote On 04/26/07 13:47,:
    >>
    >>>(Since queue.h is not a part of standard C, I'd lke to ask here)
    >>>
    >>>For example, BSD implementation of sys/queue.h has following weird
    >>>macros:
    >>>I can't understand why "do{}while(0)" is used... Removing
    >>>"do{}while(0)" from these macros should be ok. Right?

    >>
    >> The reason for the do{}while(0) dodge in multi-
    >>statement macro expansions is to make them work right
    >>in contexts where just one statement is allowed.

    >
    >
    > At the expense of contexts where no statements are allowed -- only
    > expressions.


    Right. But since there are no expressions that can
    contain statements anyhow, much less the expansion of a
    multi-statement macro, the expense is zero.

    --
    Eric.Sosman@sun.com

  7. Re: Werid <sys/queue.h> - it has useless do{} while(0)

    On Apr 26, 11:34 am, Eric Sosman wrote:

    > > #define SLIST_INIT(head) do { \
    > > SLIST_FIRST((head)) = NULL; \
    > > } while (0)


    > No reason I can see for do{}while(0) on the first
    > one, but for the next two it makes sense. Maybe the
    > first has do{}while(0) just for consistency's sake, or
    > maybe an earlier version of the first macro had more
    > than one statement.


    Consider something like "*SLIST_INIT(head);" (where the asterisk is a
    typo). With the 'do/while', this is caught by the compiler. Without
    it, the result is likely a crash at run time as SLIST_FIRST(head) is
    dereference rather than initialized.

    It is a basic design goal of macros to isolate the internals of the
    implementation semantically from anything before or after the macro
    where the macro is used. You don't want anything to spill over into
    the macro.

    Just yesterday I spend about 8 hours tracking a bug caused by exactly
    this. Two variables are *always* set as a unit, and oddly one of them
    was getting set but not the other. I suspected memory corruption and
    wasted a lot of time with 'valgrind' and similar tools. Turns out the
    problem was a macro with poor semantic isolation.

    The macro looked kind of like this:

    #define F(x) if(true) { func1(); func2(x) } else

    The intent was for the 'else' to eat the following semicolon. Sadly,
    the code looked kind of like this

    F(some_long_chunk_of_code)
    set_first_var();
    set_second_var();

    The effect was that the 'else' gobbled the 'set_first_var()' and that
    set was never executed.

    Semantic isolation in macros is an inherently good thing, even if
    there is no legal code that is affected by it. You may be the one who
    suffers when an extra '*' or missing ';' causes your macro's
    implementation to spill over into the code that uses it.

    DS


+ Reply to Thread