Function-like macro

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Russell Shaw

    #1

    Function-like macro

    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; \
    )
  • Richard Bos

    #2
    Re: Function-like macro

    Russell Shaw <rjshawN_o@s_pa m.netspace.net. au> wrote:
    [color=blue]
    > How do i make an if/then/else macro act as a function
    > so that the whole thing looks like the return value?[/color]

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

    a? What is a? What happens if I call this macro in a function where a is
    a struct?
    [color=blue]
    > } \
    > else { \
    > a = 2*b; \
    > }, \
    > a; \
    > )[/color]

    #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

    Comment

    • Russell Shaw

      #3
      Re: Function-like macro

      Richard Bos wrote:[color=blue]
      > Russell Shaw <rjshawN_o@s_pa m.netspace.net. au> wrote:
      >[color=green]
      >>How do i make an if/then/else macro act as a function
      >>so that the whole thing looks like the return value?[/color]
      >
      > You don't. That's what the ?: operator is for.
      >[color=green]
      >>I tried this lame attempt for starters:
      >>
      >>#define A_FROM_B(b) \
      >> ( \
      >> if(b < 10) { \
      >> a = b; \[/color]
      >
      > a? What is a? What happens if I call this macro in a function where a is
      > a struct?[/color]

      Like i said, it's a lame one;)
      [color=blue][color=green]
      >> } \
      >> else { \
      >> a = 2*b; \
      >> }, \
      >> a; \
      >> )[/color]
      >
      > #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[/color]

      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?

      Comment

      • Villy Kruse

        #4
        Re: Function-like macro

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

        [color=blue]
        >
        > Do i have to make it into a function?[/color]

        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

        Comment

        • Jens.Toerring@physik.fu-berlin.de

          #5
          Re: Function-like macro

          Russell Shaw <rjshawN_o@s_pa m.netspace.net. au> wrote:[color=blue]
          > Richard Bos wrote:[color=green]
          >> Russell Shaw <rjshawN_o@s_pa m.netspace.net. au> wrote:
          >>[color=darkred]
          >>>How do i make an if/then/else macro act as a function
          >>>so that the whole thing looks like the return value?[/color]
          >>
          >> You don't. That's what the ?: operator is for.
          >>[color=darkred]
          >>>I tried this lame attempt for starters:
          >>>
          >>>#define A_FROM_B(b) \
          >>> ( \
          >>> if(b < 10) { \
          >>> a = b; \[/color]
          >>
          >> a? What is a? What happens if I call this macro in a function where a is
          >> a struct?[/color][/color]
          [color=blue]
          > Like i said, it's a lame one;)[/color]
          [color=blue][color=green][color=darkred]
          >>> } \
          >>> else { \
          >>> a = 2*b; \
          >>> }, \
          >>> a; \
          >>> )[/color]
          >>
          >> #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[/color][/color]
          [color=blue]
          > What do i do with things that contain more complex statements like:[/color]
          [color=blue]
          > 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;
          > }[/color]
          [color=blue]
          > Do i have to make it into a function?[/color]

          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 ___ Jens.Toerring@p hysik.fu-berlin.de
          \______________ ____________ http://www.toerring.de

          Comment

          • CBFalconer

            #6
            Re: Function-like macro

            Russell Shaw wrote:[color=blue]
            >
            > 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; \
            > )[/color]

            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)


            Comment

            • Richard Bos

              #7
              Re: Function-like macro

              Russell Shaw <rjshawN_o@s_pa m.netspace.net. au> wrote:
              [color=blue]
              > Richard Bos wrote:[color=green]
              > > #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).[/color]
              >
              > 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?[/color]

              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

              Comment

              • Richard Bos

                #8
                Re: Function-like macro

                Villy Kruse <vek@station02. ohout.pharmapar tners.nl> wrote:
                [color=blue]
                > On Tue, 24 May 2005 20:24:28 +1000,
                > Russell Shaw <rjshawN_o@s_pa m.netspace.net. au> wrote:
                >[color=green]
                > > Do i have to make it into a function?[/color]
                >
                > 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.[/color]

                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

                Comment

                • SM Ryan

                  #9
                  Re: Function-like macro

                  Russell Shaw <rjshawN_o@s_pa m.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.

                  Comment

                  • Tim Rentsch

                    #10
                    Re: Function-like macro

                    Russell Shaw <rjshawN_o@s_pa m.netspace.net. au> writes:
                    [color=blue]
                    > 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; \
                    > )[/color]

                    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_BAROQUEL Y(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.

                    Comment

                    • Malcolm

                      #11
                      Re: Function-like macro


                      "Russell Shaw" <rjshawN_o@s_pa m.netspace.net. au> wrote[color=blue]
                      > 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; \
                      > )[/color]

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


                      Comment

                      • Dale Hagglund

                        #12
                        Re: Function-like macro

                        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.

                        Comment

                        • Russell Shaw

                          #13
                          Re: Function-like macro

                          Dale Hagglund wrote:[color=blue]
                          > 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.[/color]

                          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).

                          Comment

                          • Dale Hagglund

                            #14
                            Re: Function-like macro

                            [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.

                            Comment

                            • Jens.Toerring@physik.fu-berlin.de

                              #15
                              Re: Function-like macro

                              Russell Shaw <rjshawN_o@s_pa m.netspace.net. au> wrote:[color=blue]
                              > Dale Hagglund wrote:[color=green]
                              >> * 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.[/color][/color]
                              [color=blue]
                              > Interesting, it is in gcc-3.4 info help 5.1 Statements and Declarations in Expressions.[/color]
                              [color=blue]
                              > Does a curly-bracket block {...} have a value in standard C? I've been
                              > looking for a long time.[/color]

                              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 ___ Jens.Toerring@p hysik.fu-berlin.de
                              \______________ ____________ http://www.toerring.de

                              Comment

                              Working...