do{..}while(0) macro substitutions

Discussion in 'C Programming' started by Yan, Dec 30, 2004.

  1. Yan

    Yan Guest

    A lot of times when reading open software, i come across macros that are
    defined as follows:

    #define CALL_FUNCS(x) \
    do { \
    func1(x); \
    func2(x); \
    func3(x); \
    } while (0);

    now, of course this will work but how is this any better than:

    #define CALL_FUNCS(x) \
    { \
    func1(x); \
    func2(x); \
    func3(x); \
    }

    i can't see how the compiler can optimize (a) any better than (b) or in
    any case can (b) break what (a) won't. Any input will be appreciated.

    tia
    Yan, Dec 30, 2004
    #1
    1. Advertising

  2. Yan

    Ben Pfaff Guest

    Yan <> writes:

    > A lot of times when reading open software, i come across macros that
    > are defined as follows:
    >
    > #define CALL_FUNCS(x) \
    > do { \
    > func1(x); \
    > func2(x); \
    > func3(x); \
    > } while (0);


    Read the FAQ.
    --
    Ben Pfaff
    email:
    web: http://benpfaff.org
    Ben Pfaff, Dec 30, 2004
    #2
    1. Advertising

  3. Yan

    Alexandre Guest

    Hello,

    Yan a écrit :
    > A lot of times when reading open software, i come across macros that are
    > defined as follows:
    >
    > #define CALL_FUNCS(x) \
    > do { \
    > func1(x); \
    > func2(x); \
    > func3(x); \
    > } while (0);

    are you sure there is ";" at the end ?
    because I thought the reason why you use "do { } while(0)" is this ";" !
    you don't have to put it there, and I explain why after...

    >
    > now, of course this will work but how is this any better than:
    >
    > #define CALL_FUNCS(x) \
    > { \
    > func1(x); \
    > func2(x); \
    > func3(x); \
    > }
    >
    > i can't see how the compiler can optimize (a) any better than (b) or in
    > any case can (b) break what (a) won't. Any input will be appreciated.

    you should see where it's used in the code, and then you will understand !
    in the code you will find this :

    ....
    CALL_FUNCS(12); /* becareful of this ";" */
    ....

    so the preprocessor will replace CALL_FUNCS(12) by :
    (a)
    ....
    do { \
    func1(x); \
    func2(x); \
    func3(x); \
    } while (0); /* <- this ";" will end do { } while(0) in good way */
    ....

    (b)
    ....
    { \
    func1(12); \
    func2(12); \
    func3(12); \
    }; /* <- too much ";" */
    ....

    Maybe there is another reason, but I'm sure I read this explanation
    somewhere (maybe here).

    Alexandre
    --
    "That's what they should teach us here", he (Harry Potter) thought, ...,
    "how's girls' brains work ... it'd be more useful than Divination, anyway
    ...."

    Harry Potter and the Order of the Phoenix
    J.K. Rowling
    Alexandre, Dec 30, 2004
    #3
  4. Yan wrote:
    > A lot of times when reading open software, i come across macros that are
    > defined as follows:
    >
    > #define CALL_FUNCS(x) \
    > do { \
    > func1(x); \
    > func2(x); \
    > func3(x); \
    > } while (0);


    > now, of course this will work but how is this any better than:
    >
    > #define CALL_FUNCS(x) \
    > { \
    > func1(x); \
    > func2(x); \
    > func3(x); \
    > }
    >
    > i can't see how the compiler can optimize (a) any better than (b) or in
    > any case can (b) break what (a) won't. Any input will be appreciated.


    It is not about optimization.

    The whole idea of using 'do/while' version is to make a macro which will
    expand into a regular statement, not into a compound statement. This is
    done in order to make the use of function-style macros uniform with the
    use of ordinary functions in all contexts.

    Consider the following code sketch

    if (<condition>)
    foo(a);
    else
    bar(a);

    where 'foo' and 'bar' are ordinary functions. Now imagine that you'd
    like to replace function 'foo' with a macro of the above nature

    if (<condition>)
    CALL_FUNCS(a);
    else
    bar(a);

    Now, if your macro is defined in accordance with the second approach
    (just '{' and '}') the code will no longer compile, because the 'true'
    branch of 'i' is now represented by a compound statement. And when you
    put a ';' after this compound statement, you finished the whole 'if'
    statement, thus orphaning the 'else' branch (hence the compilation error).

    One way to correct this problem is to remember not to put ';' after
    macro "invocations"

    if (<condition>)
    CALL_FUNCS(a)
    else
    bar(a);

    This will compile and work as expected, but this is not uniform. The
    more elegant solution is to make sure that macro expand into a regular
    statement, not into a compound one. One way to achieve that is to define
    the macro as follows

    #define CALL_FUNCS(x) \
    do { \
    func1(x); \
    func2(x); \
    func3(x); \
    } while (0)

    Now this code

    if (<condition>)
    CALL_FUNCS(a);
    else
    bar(a);

    will compile without any problems.

    However, note the small but important difference between my definition
    of 'CALL_FUNCS' and the first version in your message. I didn't put a
    ';' after '} while (0)'. Putting a ';' at the end of that definition
    would immediately defeat the entire point of using 'do/while' and make
    that macro pretty much equivalent to the compound-statement version.

    I don't know why the author of the code you quoted in your original
    message put this ';' after 'while (0)'. In this form both variants are
    equivalent. The whole idea behind using 'do/while' version is not to
    include this final ';' into the macro (for the reasons that I explained
    above).

    --
    Best regards,
    Andrey Tarasevich
    Andrey Tarasevich, Dec 30, 2004
    #4
  5. Ben Pfaff wrote:

    > Yan writes:
    >
    >>A lot of times when reading open software,
    >>I come across macros that are defined as follows:
    >>
    >>#define CALL_FUNCS(x) \
    >>do { \
    >> func1(x); \
    >> func2(x); \
    >> func3(x); \
    >>} while (0);

    >
    > Read the FAQ.


    Could you please cite and quote the FAQ
    that is relevant to this question?
    E. Robert Tisdale, Dec 30, 2004
    #5
  6. Yan

    italy Guest

    It seems like this is an annoyance, so I wouldn't use any approach
    mentioned above. If you really feel the conceit to do this, then
    perhaps a function would be a better approach, even though it may
    create overhead in some cases.
    Good question.

    -Adam Roan
    "Just plain neat."
    italy, Dec 31, 2004
    #6
  7. Yan

    Dan P. Guest

    "E. Robert Tisdale" <> wrote in message
    news:cr24cs$hto$...
    > Ben Pfaff wrote:
    >
    >> Yan writes:
    >>
    >>>A lot of times when reading open software,
    >>>I come across macros that are defined as follows:
    >>>
    >>>#define CALL_FUNCS(x) \
    >>>do { \
    >>> func1(x); \
    >>> func2(x); \
    >>> func3(x); \
    >>>} while (0);

    >>
    >> Read the FAQ.

    >
    > Could you please cite and quote the FAQ
    > that is relevant to this question?



    I used Google

    http://www.google.com/

    to search for

    "comp.lang.c faq multi-statement"

    and the 1st link showed the FAQ # to be 10.4

    http://www.eskimo.com/~scs/C-faq/q10.4.html
    Dan P., Dec 31, 2004
    #7
  8. Yan wrote:

    > A lot of times when reading open software,
    > I come across macros that are defined as follows:
    >
    > #define CALL_FUNCS(x) \
    > do { \
    > func1(x); \
    > func2(x); \
    > func3(x); \
    > } while (0);


    This practice is obsolete and should be discouraged.
    Write inline function definitions instead:

    inline static
    void CALL_FUNCS(double x) {
    func1(x);
    func2(x);
    func3(x);
    }
    E. Robert Tisdale, Dec 31, 2004
    #8
  9. Yan

    Flash Gordon Guest

    Yan wrote:
    > A lot of times when reading open software, i come across macros that are
    > defined as follows:
    >
    > #define CALL_FUNCS(x) \
    > do { \
    > func1(x); \
    > func2(x); \
    > func3(x); \
    > } while (0);
    >
    > now, of course this will work but how is this any better than:
    >
    > #define CALL_FUNCS(x) \
    > { \
    > func1(x); \
    > func2(x); \
    > func3(x); \
    > }
    >
    > i can't see how the compiler can optimize (a) any better than (b) or in
    > any case can (b) break what (a) won't. Any input will be appreciated.


    Try things like:

    if (cond)
    CALL_FUNCS(a);
    else
    CALL_FUNCS(b);

    and see how far you get.
    --
    Flash Gordon
    Living in interesting times.
    Although my email address says spam, it is real and I read it.
    Flash Gordon, Dec 31, 2004
    #9
  10. "italy" <> writes:
    > It seems like this is an annoyance, so I wouldn't use any approach
    > mentioned above. If you really feel the conceit to do this, then
    > perhaps a function would be a better approach, even though it may
    > create overhead in some cases.


    It's a common C idiom that all C programmers should be familiar with.
    If you find it annoying -- well, it's not the worst annoyance in the
    language.

    --
    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, Dec 31, 2004
    #10
  11. "E. Robert Tisdale" <> writes:
    > Yan wrote:
    >
    >> A lot of times when reading open software,
    >> I come across macros that are defined as follows:
    >> #define CALL_FUNCS(x) \
    >> do { \
    >> func1(x); \
    >> func2(x); \
    >> func3(x); \
    >> } while (0);

    >
    > This practice is obsolete and should be discouraged.
    > Write inline function definitions instead:
    >
    > inline static
    > void CALL_FUNCS(double x) {
    > func1(x);
    > func2(x);
    > func3(x);
    > }


    That's great if you happen to have a compiler that supports inline
    function definitions *and* you're not concerned about your code being
    ported to a compiler that doesn't. You might have that luxury. Don't
    assume that everyone else does.

    --
    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, Dec 31, 2004
    #11
  12. Keith Thompson wrote:

    > That's great if you happen to have a compiler
    > that supports inline function definitions
    > *and* you're not concerned about your code being ported to a compiler that doesn't.
    > You might have that luxury. Don't assume that everyone else does.


    I cordially invite and welcome all comp.lang.c subscribers
    to come on into the twenty first century.
    E. Robert Tisdale, Dec 31, 2004
    #12
  13. Yan

    Mysidia Guest

    > This practice is obsolete and should be discouraged.
    > Write inline function definitions instead:


    I strongly disagree. There are certainly many cases where
    the approach is best.

    Consider this example

    #define CALL_FUNC(x, y, z) \
    do { \
    x##_fun1(y, #z); \
    x##_fun2(y, #z); \
    x##_fun3(y, #z); \
    } while(0)

    Now let how do you propose an inline function can handle
    this common sort of construct?

    By all counts, inline functions don't quite cut it for this situation.

    An inline function has to assume a specific datatype for all use
    of the macro, which somewhat restricts the input, and somewhat
    defeats major advantages of using macros.

    like
    #define MAX(a, b) ((a) > (b) ? (a) : (b))
    Is more general than

    double max(double a, double b) { return a > b ? a : b; }

    The latter treats everything as a double.
    i.e. if you called max() on two ints... you get totally unnecessary
    conversions from int to double
    Mysidia, Dec 31, 2004
    #13
  14. Yan

    Flash Gordon Guest

    E. Robert Tisdale wrote:
    > Ben Pfaff wrote:
    >
    >> Yan writes:
    >>
    >>> A lot of times when reading open software,
    >>> I come across macros that are defined as follows:
    >>>
    >>> #define CALL_FUNCS(x) \
    >>> do { \
    >>> func1(x); \
    >>> func2(x); \
    >>> func3(x); \
    >>> } while (0);

    >>
    >> Read the FAQ.

    >
    > Could you please cite and quote the FAQ
    > that is relevant to this question?


    http://www.eskimo.com/~scs/C-faq/q10.4.html

    Now why don't *you* read the FAQ.

    Oh yes, I remember now, you are a troll, that's why you don't read the FAQ.
    --
    Flash Gordon
    Living in interesting times.
    Although my email address says spam, it is real and I read it.
    Flash Gordon, Dec 31, 2004
    #14
  15. Yan wrote on 31/12/04 :
    > #define CALL_FUNCS(x) \
    > do { \
    > func1(x); \
    > func2(x); \
    > func3(x); \
    > } while (0);


    This is certainely not what you have seen. Read again, it is more
    likely:

    } while (0)

    and it's precisely the point.

    > #define CALL_FUNCS(x) \
    > { \
    > func1(x); \
    > func2(x); \
    > func3(x); \
    > }
    >
    > i can't see how the compiler can optimize (a) any better than (b) or in any
    > case can (b) break what (a) won't. Any input will be appreciated.


    It's not a question of optimization, but it's the only non invasive
    known trick that forces the user to put a ';' after the macro usage,
    making the syntax consistent.

    Nothing else.

    --
    Emmanuel
    The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
    The C-library: http://www.dinkumware.com/refxc.html

    "C is a sharp tool"
    Emmanuel Delahaye, Dec 31, 2004
    #15
  16. E. Robert Tisdale wrote on 31/12/04 :
    > Yan wrote:
    >
    >> A lot of times when reading open software,
    >> I come across macros that are defined as follows:
    >>
    >> #define CALL_FUNCS(x) \
    >> do { \
    >> func1(x); \
    >> func2(x); \
    >> func3(x); \
    >> } while (0);

    >
    > This practice is obsolete and should be discouraged.
    > Write inline function definitions instead:
    >
    > inline static
    > void CALL_FUNCS(double x) {
    > func1(x);
    > func2(x);
    > func3(x);
    > }


    Your are correct in theory, but the C-compilers installed on zillions
    of machines across the world and not magically going to switch to C99
    just because a new release of the language came out...

    --
    Emmanuel
    The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
    The C-library: http://www.dinkumware.com/refxc.html

    "Mal nommer les choses c'est ajouter du malheur au
    monde." -- Albert Camus.
    Emmanuel Delahaye, Dec 31, 2004
    #16
  17. On 30 Dec 2004 19:32:31 -0800, "Mysidia" <> wrote:

    >An inline function has to assume a specific datatype for all use
    >of the macro, which somewhat restricts the input, and somewhat
    >defeats major advantages of using macros.
    >
    >like
    >#define MAX(a, b) ((a) > (b) ? (a) : (b))
    >Is more general than
    >
    >double max(double a, double b) { return a > b ? a : b; }
    >
    >The latter treats everything as a double.
    >i.e. if you called max() on two ints... you get totally unnecessary
    >conversions from int to double


    If you use the macro MAX(a++, b), you'd invoke fairly undefined behaviour
    with one of the expressions being evaluated twice.
    Raymond Martineau, Dec 31, 2004
    #17
  18. Raymond Martineau wrote on 31/12/04 :
    > If you use the macro MAX(a++, b), you'd invoke fairly undefined behaviour
    > with one of the expressions being evaluated twice.


    A C-programmer fitted with a working brain won't write that.

    --
    Emmanuel
    The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
    The C-library: http://www.dinkumware.com/refxc.html

    "Clearly your code does not meet the original spec."
    "You are sentenced to 30 lashes with a wet noodle."
    -- Jerry Coffin in a.l.c.c++
    Emmanuel Delahaye, Dec 31, 2004
    #18
  19. "Emmanuel Delahaye" <> wrote in message
    news:...
    > Your are correct in theory, but the C-compilers installed on zillions
    > of machines across the world and not magically going to switch to C99
    > just because a new release of the language came out...


    By that argument we should all still be writing in K&R C instead of C89; one
    must draw a line somewhere, and it's perfectly valid in many cases to make
    it C99 (or C89 with very common extensions).

    S

    --
    Stephen Sprunk "Stupid people surround themselves with smart
    CCIE #3723 people. Smart people surround themselves with
    K5SSS smart people who disagree with them." --Aaron Sorkin
    Stephen Sprunk, Dec 31, 2004
    #19
  20. "Stephen Sprunk" <> writes:
    > "Emmanuel Delahaye" <> wrote in message
    > news:...
    >> Your are correct in theory, but the C-compilers installed on zillions
    >> of machines across the world and not magically going to switch to C99
    >> just because a new release of the language came out...

    >
    > By that argument we should all still be writing in K&R C instead of C89; one
    > must draw a line somewhere, and it's perfectly valid in many cases to make
    > it C99 (or C89 with very common extensions).


    As far as I know, there are very few platforms with an available K&R C
    compiler but no available C89/C90 compiler. I understand that Recent
    releases of gcc, for example, assume that the hosting compiler is C90
    compliant.

    On the other hand, there are still plenty of platforms with no
    available C99 compiler. I'd be very pleasantly surprised to discover
    that that's not the case.

    --
    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, Dec 31, 2004
    #20
    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. RJGraham
    Replies:
    6
    Views:
    480
    RJGraham
    Jun 28, 2004
  2. Chris Goller
    Replies:
    4
    Views:
    374
    Jordan Stewart
    Mar 9, 2005
  3. Tony Eva
    Replies:
    1
    Views:
    480
    Jeff Epler
    Nov 9, 2003
  4. Vivien Mallet

    Backslash substitutions

    Vivien Mallet, Sep 29, 2004, in forum: Python
    Replies:
    1
    Views:
    306
    Peter Otten
    Sep 29, 2004
  5. James S. Singleton

    Macro substitutions

    James S. Singleton, Dec 22, 2005, in forum: C Programming
    Replies:
    7
    Views:
    311
Loading...

Share This Page