Function-like macro

Discussion in 'C Programming' started by Russell Shaw, May 24, 2005.

  1. Russell Shaw

    Russell Shaw Guest

    Hi,

    How do i make an if/then/else macro act as a function
    so that the whole thing looks like the return value?

    I tried this lame attempt for starters:

    #define A_FROM_B(b) \
    ( \
    if(b < 10) { \
    a = b; \
    } \
    else { \
    a = 2*b; \
    }, \
    a; \
    )
    Russell Shaw, May 24, 2005
    #1
    1. Advertising

  2. Russell Shaw

    Richard Bos Guest

    Russell Shaw <rjshawN_o@s_pam.netspace.net.au> wrote:

    > How do i make an if/then/else macro act as a function
    > so that the whole thing looks like the return value?


    You don't. That's what the ?: operator is for.

    > I tried this lame attempt for starters:
    >
    > #define A_FROM_B(b) \
    > ( \
    > if(b < 10) { \
    > a = b; \


    a? What is a? What happens if I call this macro in a function where a is
    a struct?

    > } \
    > else { \
    > a = 2*b; \
    > }, \
    > a; \
    > )


    #define A_FROM_B(b) ((b)<10? (b): 2*(b))

    Note the parens around b in the definition of the macro. They will save
    your bacon some day when you decide to call A_FROM_B(x+10).

    Richard
    Richard Bos, May 24, 2005
    #2
    1. Advertising

  3. Russell Shaw

    Russell Shaw Guest

    Richard Bos wrote:
    > Russell Shaw <rjshawN_o@s_pam.netspace.net.au> wrote:
    >
    >>How do i make an if/then/else macro act as a function
    >>so that the whole thing looks like the return value?

    >
    > You don't. That's what the ?: operator is for.
    >
    >>I tried this lame attempt for starters:
    >>
    >>#define A_FROM_B(b) \
    >> ( \
    >> if(b < 10) { \
    >> a = b; \

    >
    > a? What is a? What happens if I call this macro in a function where a is
    > a struct?


    Like i said, it's a lame one;)

    >> } \
    >> else { \
    >> a = 2*b; \
    >> }, \
    >> a; \
    >> )

    >
    > #define A_FROM_B(b) ((b)<10? (b): 2*(b))
    >
    > Note the parens around b in the definition of the macro. They will save
    > your bacon some day when you decide to call A_FROM_B(x+10).
    >
    > Richard


    What do i do with things that contain more complex statements like:

    if(size > 0x1ff) {
    size_t sz = size;
    for(ndx = 0; ndx < 32; ndx++) {
    if(sz <= 0) {
    break;
    }
    sz >>= 1;
    }
    ndx -= 8;
    ndx <<= 9;
    }
    else {
    ndx = size;
    }

    Do i have to make it into a function?
    Russell Shaw, May 24, 2005
    #3
  4. Russell Shaw

    Villy Kruse Guest

    On Tue, 24 May 2005 20:24:28 +1000,
    Russell Shaw <rjshawN_o@s_pam.netspace.net.au> wrote:


    >
    > Do i have to make it into a function?


    An inline function wouldn't be such a bad alternative if it is available
    with your compiler. Otherwise, "do { ... } while (0)" is a common
    ideom for making a function like macro.

    Villy
    Villy Kruse, May 24, 2005
    #4
  5. Russell Shaw

    -berlin.de Guest

    Russell Shaw <rjshawN_o@s_pam.netspace.net.au> wrote:
    > Richard Bos wrote:
    >> Russell Shaw <rjshawN_o@s_pam.netspace.net.au> wrote:
    >>
    >>>How do i make an if/then/else macro act as a function
    >>>so that the whole thing looks like the return value?

    >>
    >> You don't. That's what the ?: operator is for.
    >>
    >>>I tried this lame attempt for starters:
    >>>
    >>>#define A_FROM_B(b) \
    >>> ( \
    >>> if(b < 10) { \
    >>> a = b; \

    >>
    >> a? What is a? What happens if I call this macro in a function where a is
    >> a struct?


    > Like i said, it's a lame one;)


    >>> } \
    >>> else { \
    >>> a = 2*b; \
    >>> }, \
    >>> a; \
    >>> )

    >>
    >> #define A_FROM_B(b) ((b)<10? (b): 2*(b))
    >>
    >> Note the parens around b in the definition of the macro. They will save
    >> your bacon some day when you decide to call A_FROM_B(x+10).
    >>
    >> Richard


    > What do i do with things that contain more complex statements like:


    > if(size > 0x1ff) {
    > size_t sz = size;
    > for(ndx = 0; ndx < 32; ndx++) {
    > if(sz <= 0) {
    > break;
    > }
    > sz >>= 1;
    > }
    > ndx -= 8;
    > ndx <<= 9;
    > }
    > else {
    > ndx = size;
    > }


    > Do i have to make it into a function?


    You can make a macro out of that, e.g.

    #defined STRANGE_MACRO( size, ndx ) \
    do { \
    if ( ( size ) > 0x1ff) { \
    size_t sz = ( size ); \
    for ( ndx = 0; ndx < 32; ndx++ ) { \
    if ( sz <= 0 ) \
    break; \
    sz >>= 1; \
    } \
    ndx -= 8; \
    ndx <<= 9; \
    } \
    else \
    ndx = ( size ); \
    } while ( 0 ) \

    but I would rather recommend to make that a function. Macros can
    easily break when not written and used very carefully. If you e.g.
    call it as

    STRANGE_MACRO( size++, ndx );

    then 'size' gets incremented two or three times instead of just
    once as you would expect from a function call because a macro i
    a simple text replacement (you could avoid that here by introdu-
    cing another variable in the block and assigning the value of
    'size' to it just once instead of evaluating it several times
    in the macro). And, of course, if you try to call it like this

    STRANGE_MACRO( size, ndx + 1 );

    you'll ge a syntax error that's probably very hard to find. So why
    not make the whole thing into a function?

    BTW, in that macro you use a shift operation on 'sz' but also test
    it for being less or equal to 0. But you can only use shift operations
    safely on unsigned integers.
    Regards, Jens
    --
    \ Jens Thoms Toerring ___ -berlin.de
    \__________________________ http://www.toerring.de
    -berlin.de, May 24, 2005
    #5
  6. Russell Shaw

    CBFalconer Guest

    Russell Shaw wrote:
    >
    > How do i make an if/then/else macro act as a function
    > so that the whole thing looks like the return value?
    >
    > I tried this lame attempt for starters:
    >
    > #define A_FROM_B(b) \
    > ( \
    > if(b < 10) { \
    > a = b; \
    > } \
    > else { \
    > a = 2*b; \
    > }, \
    > a; \
    > )


    try:

    #define A_FROM_B(b) do {\
    if (b < 10) a = b; \
    else { \
    a = 2*b; \
    } \
    } while (0)

    The general form is "do { <stuff> } while (0)", and you are free to
    write legal code for <stuff>. It does not return a usable value.

    --
    Some useful references about C:
    <http://www.ungerhu.com/jxh/clc.welcome.txt>
    <http://www.eskimo.com/~scs/C-faq/top.html>
    <http://benpfaff.org/writings/clc/off-topic.html>
    <http://anubis.dkuug.dk/jtc1/sc22/wg14/www/docs/n869/> (C99)
    <http://www.dinkumware.com/refxc.html> (C-library}
    <http://gcc.gnu.org/onlinedocs/> (GNU docs)
    CBFalconer, May 24, 2005
    #6
  7. Russell Shaw

    Richard Bos Guest

    Russell Shaw <rjshawN_o@s_pam.netspace.net.au> wrote:

    > Richard Bos wrote:
    > > #define A_FROM_B(b) ((b)<10? (b): 2*(b))
    > >
    > > Note the parens around b in the definition of the macro. They will save
    > > your bacon some day when you decide to call A_FROM_B(x+10).

    >
    > What do i do with things that contain more complex statements like:
    >
    > if(size > 0x1ff) {
    > size_t sz = size;
    > for(ndx = 0; ndx < 32; ndx++) {
    > if(sz <= 0) {
    > break;
    > }
    > sz >>= 1;
    > }
    > ndx -= 8;
    > ndx <<= 9;
    > }
    > else {
    > ndx = size;
    > }
    >
    > Do i have to make it into a function?


    Have to is strong, but in practice that would be the best solution.
    Modern compilers are quite good at optimising, so a function this size
    would probably be inlined automatically wherever that is more efficient.

    Richard
    Richard Bos, May 24, 2005
    #7
  8. Russell Shaw

    Richard Bos Guest

    Villy Kruse <> wrote:

    > On Tue, 24 May 2005 20:24:28 +1000,
    > Russell Shaw <rjshawN_o@s_pam.netspace.net.au> wrote:
    >
    > > Do i have to make it into a function?

    >
    > An inline function wouldn't be such a bad alternative if it is available
    > with your compiler. Otherwise, "do { ... } while (0)" is a common
    > ideom for making a function like macro.


    True, but it has one drawback: you can't return a value from one, so it
    acts as a statement block, not as a function call.

    Richard
    Richard Bos, May 24, 2005
    #8
  9. Russell Shaw

    SM Ryan Guest

    Russell Shaw <rjshawN_o@s_pam.netspace.net.au> wrote:
    # Hi,
    #
    # How do i make an if/then/else macro act as a function
    # so that the whole thing looks like the return value?

    You can turn the following statements into expressions. If you mind the precedence,
    you can reduce the number of parentheses.

    a; b (a,b)
    {a} (a)
    if (a) b; else c ((a)?(b):(c))
    expression; (expression)

    With declarations and other statements, you're screwed.

    Note that "a = b" is an expression. The statement "a = b;" can be converted to
    "a = b".

    # #define A_FROM_B(b) \
    # ( \
    # if(b < 10) { \
    # a = b; \
    # } \
    # else { \
    # a = 2*b; \
    # }, \
    # a; \
    # )

    ( \
    (b < 10) ? ( \
    a = b \
    ) \
    : ( \
    a = 2*b \
    ), \
    a \
    )

    --
    SM Ryan http://www.rawbw.com/~wyrmwif/
    Elvis was an artist. But that didn't stop him from joining the service
    in time of war. That's why he is the king, and you're a shmuck.
    SM Ryan, May 24, 2005
    #9
  10. Russell Shaw

    Tim Rentsch Guest

    Russell Shaw <rjshawN_o@s_pam.netspace.net.au> writes:

    > How do i make an if/then/else macro act as a function
    > so that the whole thing looks like the return value?
    >
    > I tried this lame attempt for starters:
    >
    > #define A_FROM_B(b) \
    > ( \
    > if(b < 10) { \
    > a = b; \
    > } \
    > else { \
    > a = 2*b; \
    > }, \
    > a; \
    > )


    Many macros written in statement form can be written fairly easily in
    expression form instead. Is there any reason

    #define A_FROM_B(b) (a = (b)<10 ? (b) : 2*(b))

    doesn't meet your needs in this case?

    As a matter of good form I'd usually prefer that the assigned-to
    variable be made explicit:

    #define ASSIGN_BAROQUELY(a,b) ((a) = (b)<10 ? (b) : 2*(b))

    but that is a separate discussion.

    Those macro definitions that can't be written in expression form and
    that need to return a value are probably better written as functions,
    whether inline functions are available or not.
    Tim Rentsch, May 24, 2005
    #10
  11. Russell Shaw

    Malcolm Guest

    "Russell Shaw" <rjshawN_o@s_pam.netspace.net.au> wrote
    > How do i make an if/then/else macro act as a function
    > so that the whole thing looks like the return value?
    >
    > I tried this lame attempt for starters:
    >
    > #define A_FROM_B(b) \
    > ( \
    > if(b < 10) { \
    > a = b; \
    > } \
    > else { \
    > a = 2*b; \
    > }, \
    > a; \
    > )


    #define A_FROM_B(b) ((b) < 10 ? (b) : (2 * (b)))
    Malcolm, May 24, 2005
    #11
  12. Russell> How do i make an if/then/else macro act as a function so
    Russell> that the whole thing looks like the return value?

    Others have already pointed out that you're probably much better off
    using an inline function. It's more easily readable and editable.
    That said, GCC does have a non-standard extension that allows you to
    do what you want:

    #define A_FROM_B(b) \
    ({ \
    int __b = (b); \
    int __a; \
    if (__b < 10) \
    __a = __b; \
    else \
    __a = 2*__b; \
    __a; \
    })

    A few notes:

    * I haven't compiled the above code so I may have a couple of
    typos in it. See Statement Exprs in the gcc info pages.

    * I introduced the __b variable to prevent multiple evaluation
    of b. (Functions get you this for free, of course.)

    * The value of the macro is the the last "bare" expression in
    the block.

    * As I mentioned, as far as I know this is non-standard.

    * GCC has a couple of other nifty extensions that work well
    together with this extension. Especially see the gcc info
    on typeof().

    * Because macros are based on textual substitution, it's a
    good idea to introduce local variable names that aren't
    likely to collide with names used inside the macro
    arguments. (Again, functions completely avoid this issue.)

    Dale.
    Dale Hagglund, May 25, 2005
    #12
  13. Russell Shaw

    Russell Shaw Guest

    Dale Hagglund wrote:
    > Russell> How do i make an if/then/else macro act as a function so
    > Russell> that the whole thing looks like the return value?
    >
    > Others have already pointed out that you're probably much better off
    > using an inline function. It's more easily readable and editable.
    > That said, GCC does have a non-standard extension that allows you to
    > do what you want:
    >
    > #define A_FROM_B(b) \
    > ({ \
    > int __b = (b); \
    > int __a; \
    > if (__b < 10) \
    > __a = __b; \
    > else \
    > __a = 2*__b; \
    > __a; \
    > })
    >
    > A few notes:
    >
    > * I haven't compiled the above code so I may have a couple of
    > typos in it. See Statement Exprs in the gcc info pages.
    >
    > * I introduced the __b variable to prevent multiple evaluation
    > of b. (Functions get you this for free, of course.)
    >
    > * The value of the macro is the the last "bare" expression in
    > the block.
    >
    > * As I mentioned, as far as I know this is non-standard.
    >
    > * GCC has a couple of other nifty extensions that work well
    > together with this extension. Especially see the gcc info
    > on typeof().
    >
    > * Because macros are based on textual substitution, it's a
    > good idea to introduce local variable names that aren't
    > likely to collide with names used inside the macro
    > arguments. (Again, functions completely avoid this issue.)
    >
    > Dale.


    Interesting, it is in gcc-3.4 info help 5.1 Statements and Declarations in Expressions.

    Does a curly-bracket block {...} have a value in standard C? I've been looking for
    a long time.

    The macro above works (i tested it).
    Russell Shaw, May 25, 2005
    #13
  14. [My example of gcc statement expression syntax deleted. --rdh]

    Russell> Does a curly-bracket block {...} have a value in standard
    Russell> C?

    Nope. As far as I know its a gcc-only extension.

    Dale.
    Dale Hagglund, May 25, 2005
    #14
  15. Russell Shaw

    -berlin.de Guest

    Russell Shaw <rjshawN_o@s_pam.netspace.net.au> wrote:
    > Dale Hagglund wrote:
    >> * The value of the macro is the the last "bare" expression in
    >> the block.
    >>
    >> * As I mentioned, as far as I know this is non-standard.


    > Interesting, it is in gcc-3.4 info help 5.1 Statements and Declarations in Expressions.


    > Does a curly-bracket block {...} have a value in standard C? I've been
    > looking for a long time.


    No, a block (compound statement) isn't an expression and thus has no
    value. So something like

    int i = { 1; };

    or

    int i = ( { 1; } );

    or variations of these aren't standard C. gcc lets you use the second
    version, i.e. a compound statement enclosed in parentheses where the
    value of the last expression in the block is taken to be the value of
    of the whole construct, as an extension only (that's why it is listed
    in the info pages under "C Extensions";-)

    Regards, Jens
    --
    \ Jens Thoms Toerring ___ -berlin.de
    \__________________________ http://www.toerring.de
    -berlin.de, May 25, 2005
    #15
  16. Russell Shaw

    Richard Bos Guest

    Dale Hagglund <> wrote:

    > Others have already pointed out that you're probably much better off
    > using an inline function. It's more easily readable and editable.
    > That said, GCC does have a non-standard extension that allows you to
    > do what you want:
    >
    > #define A_FROM_B(b) \
    > ({ \
    > int __b = (b); \
    > int __a; \
    > if (__b < 10) \
    > __a = __b; \
    > else \
    > __a = 2*__b; \
    > __a; \
    > })


    > * I introduced the __b variable to prevent multiple evaluation
    > of b. (Functions get you this for free, of course.)


    Unfortunately it also makes the macro non-portable, since all
    identifiers starting with __ (or _ plus capital letter) are reserved for
    the implementation. __b is simple enough that it could clash with
    something defined in a system header.

    > * As I mentioned, as far as I know this is non-standard.


    'tis.

    > * Because macros are based on textual substitution, it's a
    > good idea to introduce local variable names that aren't
    > likely to collide with names used inside the macro
    > arguments. (Again, functions completely avoid this issue.)


    But make sure they're yours to use.

    Richard
    Richard Bos, May 26, 2005
    #16
  17. Russell Shaw

    pete Guest

    Richard Bos wrote:

    > #define A_FROM_B(b) ((b)<10? (b): 2*(b))
    >
    > Note the parens around b in the definition of the macro.
    > They will save
    > your bacon some day when you decide to call A_FROM_B(x+10).


    Trivia point:
    Only the first and last pair are needed for bacon saving.

    #define A_FROM_B(b) ((b) < 10 ? b : 2 * (b))

    ? b :
    means the same thing as
    ?(b):

    --
    pete
    pete, May 27, 2005
    #17
  18. Russell Shaw

    Richard Bos Guest

    pete <> wrote:

    > Richard Bos wrote:
    >
    > > #define A_FROM_B(b) ((b)<10? (b): 2*(b))
    > >
    > > Note the parens around b in the definition of the macro.
    > > They will save
    > > your bacon some day when you decide to call A_FROM_B(x+10).

    >
    > Trivia point:
    > Only the first and last pair are needed for bacon saving.
    >
    > #define A_FROM_B(b) ((b) < 10 ? b : 2 * (b))
    >
    > ? b :
    > means the same thing as
    > ?(b):


    In this case, perhaps. Howsoever, I'd advise getting into the habit of
    parenthesisising anyway, for psychobabblical reasons.

    Richard
    Richard Bos, May 27, 2005
    #18
    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. baumann@pan

    why function like macro doesn't work here?

    baumann@pan, Jul 8, 2005, in forum: C Programming
    Replies:
    8
    Views:
    479
    Sensei
    Jul 15, 2005
  2. baumann@pan

    why function like macro doesn't work here?

    baumann@pan, Jul 8, 2005, in forum: C Programming
    Replies:
    1
    Views:
    302
    Artie Gold
    Jul 8, 2005
  3. Patrick Kowalzick
    Replies:
    5
    Views:
    470
    Patrick Kowalzick
    Mar 14, 2006
  4. He Shiming
    Replies:
    0
    Views:
    290
    He Shiming
    Aug 1, 2006
  5. , India

    inline function vs function-like macro

    , India, Mar 6, 2007, in forum: C Programming
    Replies:
    2
    Views:
    634
    Flash Gordon
    Mar 6, 2007
Loading...

Share This Page