Opinion: macros and why they're bad

M

Michael Winter

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.uk (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):
#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)

Macros are bad.

-----
Jack Klein (in response to the original post):
#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)

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?
 
K

Kevin Goodsell

Michael said:
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?

A global variable is certainly preferable to 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),

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_CONSTANT 42

// some_header.h
#undef MY_IMPORTANT_CONSTANT
#define MY_IMPORTANT_CONSTANT 3

// main.cpp
#include "my_header.h"
#include "some_header.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
 
A

Alf P. Steinbach

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?

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.

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?

See above.

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?

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.



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

See above.


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

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<typename T> T inline square( T x ){ return x*x; }

And so on.
 
D

David White

Michael Winter said:
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?

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

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*DEPTH;
//...
}

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
 
J

Joe Simon

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


#ifdef DATALOGGER_ACTIVE

#pragma message ( "Compiling with Data Logger" )

#define PUT_MSG( errorName, functionName, Data ) \
DataLogger::put ( errorName, \
MacroComponentName + 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_ACTIVE 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
 
K

Kevin Goodsell

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


#ifdef DATALOGGER_ACTIVE

#pragma message ( "Compiling with Data Logger" )

#define PUT_MSG( errorName, functionName, Data ) \
DataLogger::put ( errorName, \
MacroComponentName + CString ( "." ) + MacroClassName, \
functionName, \
Data ) ;

#else

#pragma message ( "Compiling without Data Logger" )

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

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

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

*** file: log_off.cpp
void put_msg(const std::string &errorName, const std::string
&functionName, 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_ACTIVE
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
 
?

=?iso-8859-1?Q?Juli=E1n?= Albo

Joe Simon escribió:
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_ACTIVE to false andall
of the code associated with the logging calls get removed from the
application.
How would I accomplish this without mcaros ?

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

jeffc

Michael Winter said:
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?

Those have types too.
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).

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

David White

[snip]
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_ACTIVE to false and all
of the code associated with the logging calls get removed from the
application.
How would I accomplish this without mcaros ?

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,142
Messages
2,570,819
Members
47,367
Latest member
mahdiharooniir

Latest Threads

Top