Opinion: macros and why they're bad

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Michael Winter

    Opinion: macros and why they're bad

    In a recent post ("About C error" by Victor, 21 Sep 2003), comments were
    made about the poster's use of macros. What I would like to know is why
    they are considered bad? I'm not referring to their use as 'functions'; I
    realise the loss of type-safety and the possible evaluation errors that can
    occur. However, what would be the harm with numeric and text literals?

    Consider a number that plays a significant role in the implementation of an
    algorithm, and in that implementation the number is required in two, or
    more, different scopes. There wouldn't be much point in declaring a
    const-qualified variable in both scopes as it spoils a benefit of
    identifying such 'magic' numbers - defining it in a single, easily locatable
    position (for maintenance). In such a case, would you even consider waiving
    the 'no globals' recommendation just to avoid the use of a macro?

    Would performance, or in fact anything, really be adversely affected by the
    use of a macro instead of a const-qualified variable?

    Just out of plain curiosity (as I use macros, as described above, myself),
    Mike

    --
    Michael Winter
    M.Winter@[no-spam]blueyonder.co.u k (remove [no-spam] to reply)


    The comments I refer to follow. Please note that no offence to the posters
    is intended. I am simply using their comments as examples (I don't have any
    others to hand).


    Kevin Goodsell (in response to the original post):
    [color=blue]
    > #define MAXVERTICES (20) /*Maximum number of object's vertices*/
    > #define MAXFILENAME (20) /*Maximum characters of file's name*/
    > #define MAXDATA (40) //Maximum data can be read
    > #define M (256)
    > #define N (256)[/color]

    Macros are bad.

    -----
    Jack Klein (in response to the original post):
    [color=blue]
    > #define MAXVERTICES (20) /*Maximum number of object's vertices*/
    > #define MAXFILENAME (20) /*Maximum characters of file's name*/
    > #define MAXDATA (40) //Maximum data can be read
    > #define M (256)
    > #define N (256)[/color]

    Why are you putting parentheses around simple text macros like this?
    It can't do you any good, and it just might cause problems in some
    instances, although I can't think of any off-hand.

    Since you are compiling with a C++ compiler, why not use constant
    variables instead?


  • Kevin Goodsell

    #2
    Re: Opinion: macros and why they're bad

    Michael Winter wrote:[color=blue]
    > In a recent post ("About C error" by Victor, 21 Sep 2003), comments were
    > made about the poster's use of macros. What I would like to know is why
    > they are considered bad? I'm not referring to their use as 'functions'; I
    > realise the loss of type-safety and the possible evaluation errors that can
    > occur. However, what would be the harm with numeric and text literals?
    >
    > Consider a number that plays a significant role in the implementation of an
    > algorithm, and in that implementation the number is required in two, or
    > more, different scopes. There wouldn't be much point in declaring a
    > const-qualified variable in both scopes as it spoils a benefit of
    > identifying such 'magic' numbers - defining it in a single, easily locatable
    > position (for maintenance). In such a case, would you even consider waiving
    > the 'no globals' recommendation just to avoid the use of a macro?[/color]

    A global variable is certainly preferable to a macro.
    [color=blue]
    >
    > Would performance, or in fact anything, really be adversely affected by the
    > use of a macro instead of a const-qualified variable?
    >
    > Just out of plain curiosity (as I use macros, as described above, myself),[/color]

    Macros modify the code "behind your back" before the compiler sees it.
    This makes problems harder to locate.

    Macros require more care when defining them, so they allow more
    opportunity for mistakes:

    #define SUM = a + b // woops, forgot parens
    int val = SUM * 2; // wrong result

    Macros don't obey scoping rules.

    #define my_const 5

    void func()
    {
    const int my_const = 7; // woops, error.
    }

    Macros can be redefined.

    // my_header.h
    #define MY_IMPORTANT_CO NSTANT 42

    // some_header.h
    #undef MY_IMPORTANT_CO NSTANT
    #define MY_IMPORTANT_CO NSTANT 3

    // main.cpp
    #include "my_header. h"
    #include "some_heade r.h"

    Macros don't have types.

    #define NULL_PTR 0
    void f(int);
    void f(char *);

    f(NULL_PTR); // woops, probably calling the wrong function

    // another example:

    #define MY_STRING "This is a string"

    char *p = MY_STRING; // woops! Could have been diagnosed
    // if const had been used

    Most uses of macros can be replaced with language features that are
    better-behaved, so why would you want to stick with macros?

    -Kevin
    --
    My email address is valid, but changes periodically.
    To contact me please use the address from a recent posting.

    Comment

    • Alf P. Steinbach

      #3
      Re: Opinion: macros and why they're bad

      On Sun, 21 Sep 2003 23:34:14 GMT, "Michael Winter" <M.Winter@[no-spam]blueyonder.co.u k> wrote:
      [color=blue]
      >In a recent post ("About C error" by Victor, 21 Sep 2003), comments were
      >made about the poster's use of macros. What I would like to know is why
      >they are considered bad?[/color]

      Because macros are text substitution, and since macros don't live in
      namespaces you cannot avoid the ones you don't want.

      Concrete example: Microsoft's GDI+ graphics API has a header file that
      requires macros "min" and "max", which clash with the standard C++ library.

      Also, macros are not type-safe, not evaluation safe (esp. wrt. side effects),
      not suited for debugging, do not follow ordinary syntax neither in definition
      nor in usage, and and and.

      [color=blue]
      >I'm not referring to their use as 'functions'; I
      >realise the loss of type-safety and the possible evaluation errors that can
      >occur. However, what would be the harm with numeric and text literals?[/color]

      See above.

      [color=blue]
      >Consider a number that plays a significant role in the implementation of an
      >algorithm, and in that implementation the number is required in two, or
      >more, different scopes. There wouldn't be much point in declaring a
      >const-qualified variable in both scopes as it spoils a benefit of
      >identifying such 'magic' numbers - defining it in a single, easily locatable
      >position (for maintenance). In such a case, would you even consider waiving
      >the 'no globals' recommendation just to avoid the use of a macro?[/color]

      There is no recommendation to avoid global constants. It's a good idea to
      put them in a namespace, though, if they're going to be used in more than
      one compilation unit. In short, there's no need for macros for that.



      [color=blue]
      >Would performance, or in fact anything, really be adversely affected by the
      >use of a macro instead of a const-qualified variable?[/color]

      See above.


      [color=blue]
      >Just out of plain curiosity (as I use macros, as described above, myself),[/color]

      Don't. ;-)

      Macros are sometimes necessary, but not for things which there are very
      good language constructs for.

      * DON'T: #define MYTEXT "Pling plong"
      DO: char const myText[] = "Pling Plong";

      * DON'T: #define NMAX 5
      DO: std::size_t const nMax = 5;

      * DON'T: #define SQUARE( x ) (x)*(x)
      DO: template<typena me T> T inline square( T x ){ return x*x; }

      And so on.

      Comment

      • David White

        #4
        Re: Opinion: macros and why they're bad

        Michael Winter <M.Winter@[no-spam]blueyonder.co.u k> wrote in message
        news:Wzqbb.1591 $8k6.15991900@n ews-text.cableinet. net...[color=blue]
        > In a recent post ("About C error" by Victor, 21 Sep 2003), comments were
        > made about the poster's use of macros. What I would like to know is why
        > they are considered bad? I'm not referring to their use as 'functions'; I
        > realise the loss of type-safety and the possible evaluation errors that[/color]
        can[color=blue]
        > occur. However, what would be the harm with numeric and text literals?
        >
        > Consider a number that plays a significant role in the implementation of[/color]
        an[color=blue]
        > algorithm, and in that implementation the number is required in two, or
        > more, different scopes. There wouldn't be much point in declaring a
        > const-qualified variable in both scopes as it spoils a benefit of
        > identifying such 'magic' numbers - defining it in a single, easily[/color]
        locatable[color=blue]
        > position (for maintenance). In such a case, would you even consider[/color]
        waiving[color=blue]
        > the 'no globals' recommendation just to avoid the use of a macro?[/color]

        The argument is mostly against global _variables_, not global constants. Why
        do you think a global constant is bad but a global macro is okay? Anyway,
        you can put a constant in a namespace if you want. You can't confine a
        macro's scope at all.
        [color=blue]
        > Would performance, or in fact anything, really be adversely affected by[/color]
        the[color=blue]
        > use of a macro instead of a const-qualified variable?
        >
        > Just out of plain curiosity (as I use macros, as described above, myself),[/color]

        Macros are a text-replacement facility. If you use them, the source code you
        see isn't what the C++ parser gets. Try compiling this:
        #define WIDTH 5.6
        #define HEIGHT 4..1
        #define DEPTH 7.9

        void f()
        {
        double volume = WIDTH*HEIGHT*DE PTH;
        //...
        }

        VC++ 6.0 says:
        z.cpp(7) : error C2143: syntax error : missing ';' before 'constant'

        Line 7 is perfectly in order, but this is what you get for using macros. If
        you replace the macros with:

        const double WIDTH = 5.6;
        const double HEIGHT = 4..1;
        const double DEPTH = 7.9;

        VC++ 6.0 says:
        z.cpp(2) : error C2143: syntax error : missing ';' before 'constant'

        At least you now know where the error really is.

        It seems self-evident that the more different the code you edit is from the
        code received by the C++ parser, the more problems you are going to get in
        code maintenance, compiling and debugging.

        DW



        Comment

        • Joe Simon

          #5
          Re: Opinion: macros and why they're bad

          OK guys... can you come up with an easy, non macro way, to perform the
          following ?


          #ifdef DATALOGGER_ACTI VE

          #pragma message ( "Compiling with Data Logger" )

          #define PUT_MSG( errorName, functionName, Data ) \
          DataLogger::Put ( errorName, \
          MacroComponentN ame + CString ( "." ) + MacroClassName, \
          functionName, \
          Data ) ;

          #else

          #pragma message ( "Compiling without Data Logger" )

          #define PUT_MSG( errorName, functionName, Data )
          #endif

          This macro PUT_MSG is used throughout the code to provide a multi level data
          loggin mechanism to monitor the application during runtime. It is
          controllable on an individual compilation unit level, so as a level
          completes dubugging and test you can set DATALOGGER_ACTI VE to false and all
          of the code associated with the logging calls get removed from the
          application.
          How would I accomplish this without mcaros ?

          Thanks
          Joe Simon


          Comment

          • Kevin Goodsell

            #6
            Re: Opinion: macros and why they're bad

            Joe Simon wrote:
            [color=blue]
            > OK guys... can you come up with an easy, non macro way, to perform the
            > following ?
            >
            >
            > #ifdef DATALOGGER_ACTI VE
            >
            > #pragma message ( "Compiling with Data Logger" )
            >
            > #define PUT_MSG( errorName, functionName, Data ) \
            > DataLogger::Put ( errorName, \
            > MacroComponentN ame + CString ( "." ) + MacroClassName, \
            > functionName, \
            > Data ) ;
            >
            > #else
            >
            > #pragma message ( "Compiling without Data Logger" )
            >
            > #define PUT_MSG( errorName, functionName, Data )
            > #endif
            >[/color]

            *** file: logging.h
            #include <string>
            void put_msg(const std::string &errorName, const std::string
            &functionNam e, const std::string &Data);

            *** file: log_on.cpp
            void put_msg(const std::string &errorName, const std::string
            &functionNam e, const std::string &Data)
            {
            // implement function here
            }

            *** file: log_off.cpp
            void put_msg(const std::string &errorName, const std::string
            &functionNam e, const std::string &Data)
            {
            // do nothing
            }

            Now you link against the file containing the logging function you want.
            You can even provide other, new logging functions without modifying
            existing code.

            Conditional compilation is one of those things that you can't do without
            macros. But you should be very careful with it, because it can lead to
            code that is horribly ugly and difficult to understand. I think your
            example is a mostly acceptable use - it's much better than littering
            your code with things like this:

            void func()
            {

            #ifdef DATALOGGER_ACTI VE
            write_log(/* whatever */);
            #endif

            // ...
            }

            It gets even worse when you need two different sections of code - one
            for when the logger is active and one for when it's inactive. It gets
            worse still if there are a lot of these conditionally compiled sections,
            or if the sections are long. If you really need multiple configurations
            which are that different, it's probably best to encapsulate the
            functionality somehow and provide multiple implementations that do the
            right thing for each configuration.

            -Kevin
            --
            My email address is valid, but changes periodically.
            To contact me please use the address from a recent posting.

            Comment

            • Julián Albo

              #7
              Re: Opinion: macros and why they're bad

              Joe Simon escribió:
              [color=blue]
              > This macro PUT_MSG is used throughout the code to provide a multi leveldata
              > loggin mechanism to monitor the application during runtime. It is
              > controllable on an individual compilation unit level, so as a level
              > completes dubugging and test you can set DATALOGGER_ACTI VE to false andall
              > of the code associated with the logging calls get removed from the
              > application.
              > How would I accomplish this without mcaros ?[/color]

              Use a inline function instead. And if you want to avoid even the macro
              used for the ifdef you can use a const varaible and an if on it, and the
              optimizer will take care that not code is generated when not needed.

              Regards.

              Comment

              • jeffc

                #8
                Re: Opinion: macros and why they're bad


                "Michael Winter" <M.Winter@[no-spam]blueyonder.co.u k> wrote in message
                news:Wzqbb.1591 $8k6.15991900@n ews-text.cableinet. net...[color=blue]
                > In a recent post ("About C error" by Victor, 21 Sep 2003), comments were
                > made about the poster's use of macros. What I would like to know is why
                > they are considered bad? I'm not referring to their use as 'functions'; I
                > realise the loss of type-safety and the possible evaluation errors that[/color]
                can[color=blue]
                > occur. However, what would be the harm with numeric and text literals?[/color]

                Those have types too.
                [color=blue]
                > Consider a number that plays a significant role in the implementation of[/color]
                an[color=blue]
                > algorithm, and in that implementation the number is required in two, or
                > more, different scopes. There wouldn't be much point in declaring a
                > const-qualified variable in both scopes as it spoils a benefit of
                > identifying such 'magic' numbers - defining it in a single, easily[/color]
                locatable[color=blue]
                > position (for maintenance).[/color]

                You would just declare a single const that is accessible in both scopes,
                just like you'd declare a single macro that was accessible to both pieces of
                source code.


                Comment

                • David White

                  #9
                  Re: Opinion: macros and why they're bad

                  Joe Simon <jb.simon@lmco. com> wrote in message
                  news:bknbf3$h0e 1@cui1.lmms.lmc o.com...

                  [snip]
                  [color=blue]
                  > This macro PUT_MSG is used throughout the code to provide a multi level[/color]
                  data[color=blue]
                  > loggin mechanism to monitor the application during runtime. It is
                  > controllable on an individual compilation unit level, so as a level
                  > completes dubugging and test you can set DATALOGGER_ACTI VE to false and[/color]
                  all[color=blue]
                  > of the code associated with the logging calls get removed from the
                  > application.
                  > How would I accomplish this without mcaros ?[/color]

                  You've already received a non-macro alternative from Kevin Goodsell, but I
                  just wanted to point out that the OP's question was confined to numerical
                  and text literals, which is the context in which I responded. I don't claim
                  that there is never an occasion when you need a macro.

                  DW



                  Comment

                  Working...