Thoughts on defines and macros in C++, should they be used?

Started by
23 comments, last by hellfire 20 years, 7 months ago
I was just wondering what people thought about using macros and defines in Object oriented programming and in C++. I am asking because someone I know at work is using macros to define macros and making entire files that are just macros. Shouldn't good OO design really remove the need for macros? I am not sure, just asking. [edited by - hellfire on September 1, 2003 2:05:29 AM]
Advertisement
I use defines in my code though I do try to keep their use to a minimum. There are just some things that I cannot see doing any better way.

I find that defines make the code a LOT more clear.
For instance, my current protect. Networking code that has to recognize many different packet types. You tell me which is clearer?

if (Packet.Type == GENERIC_PACKET)
{
}
else if (Packet.Type == MOVE_PACKET)
{
}

OR

if (Packet.Type == 0)
{
}
else if (Packet.Type == 1)
{
}


Now the use of macros to mace macros thing is another story all together... Still don''t think they should be done away with all together though.

Webby
There are some things macros can do that other things in C++ can't do. But making such heavy use of them is pretty suspicious. They're not THAT useful. Maybe he doesn't know of inline functions or templates -- Those together remove many of the uses for macros. (edit: or 'const', as the post above mine shows)

As for OO.. It certainly doesn't solve every problem in programming, no matter how good OO design you have! There are many things that can be made a hell of a lot more elegantly with alternative approaches. OO and macros are so different things that you can't really say OO would solve what macros do or vice versa.

[edited by - civguy on September 1, 2003 2:49:53 AM]
quote:Original post by WebsiteWill
if (Packet.Type == GENERIC_PACKET)
{
}
else if (Packet.Type == MOVE_PACKET)
{
}
You don''t need macros. You need const.

const int GENERIC_PACKET = 0;
const int MOVE_PACKET = 1;

Or, even better, an enum:

enum PacketIds { GENERIC_PACKET, MOVE_PACKET };

Now you don''t even have to type the indices, since enum automatically makes increasing indices.

I have three macros defined

#ifdef DEBUG
#define SETDEBUG(X) X
#else
#define SETDEBUG(X) /*X*/
#endif
#define nSETDEBUG(X) /*X*/
#define DEBUGOUT(X) {DebugSystem::Stream << X; DebugSystem::Stream.flush( );}

Then, at the beginning of my files I just define all the output macros I need, such as

#define VIDEO_TEST_LOG(X) SETDEBUG(DEBUGOUT(X))

In my code, I can call anywhere :

VIDEO_TEST_LOG( "\n [video error] " << Object.name << " Failed at test #" << TestNumber )

When I don''t need debug output anymore, I undefine DEBUG.
When I don''t need a specific output anymore, I define it to nSETDEBUG insetead, like this:

#define UNUSED_LOG(X) nSETDEBUG(DEBUGOUT(X))

This way, I can change a single letter to get it working again. And besides, all this takes is one line per output. Finally, since in the release version all these are commented out, there''s no need to worry about which are getting compiled into the final binary.

ToohrVyk

I can see using macros, in some the cases you guys showed. I can see where they could be replaced with other coding practices.

Okay, here is my real question, this guy as far as I can tell, is using macros instead of using objects and inhertance. ( I wish I could post the code, but I can''t.) Does anyone think that is okay?
quote:Original post by ToohrVyk
I have three macros defined

#ifdef DEBUG
#define SETDEBUG(X) X
#else
#define SETDEBUG(X) /*X*/
#endif
#define nSETDEBUG(X) /*X*/
#define DEBUGOUT(X) {DebugSystem::Stream << X; DebugSystem::Stream.flush( );}

Then, at the beginning of my files I just define all the output macros I need, such as

#define VIDEO_TEST_LOG(X) SETDEBUG(DEBUGOUT(X))

In my code, I can call anywhere :

VIDEO_TEST_LOG( "\n [video error] " << Object.name << " Failed at test #" << TestNumber )

When I don't need debug output anymore, I undefine DEBUG.
When I don't need a specific output anymore, I define it to nSETDEBUG insetead, like this:

#define UNUSED_LOG(X) nSETDEBUG(DEBUGOUT(X))

This way, I can change a single letter to get it working again. And besides, all this takes is one line per output. Finally, since in the release version all these are commented out, there's no need to worry about which are getting compiled into the final binary.

ToohrVyk



Why not use have a debug class, have the debug functions in there, and make instance of it all the files that would use it? Or make it the base class? That way you just delete the instance of it, but you still have the class for other projects. I see how macros can be useful, but I can see how you wouldn't need one either.

[edited by - Hellfire on September 1, 2003 3:44:36 AM]
quote:Original post by hellfire

Why not use have a debug class, have the debug functions in there, and make instance of it all the files that would use it? Or make it the base class? That way you just delete the instance of it, but you still have the class for other projects. I see how macros can be useful, but I can see how you wouldn''t need one either.


If you did that you''d have calls to a debugging class spread throughout your application. When it came time to ship a production version of your program, it''d still have that debugging stuff in it, potentially slowing things down. Even if you later made it so all the debugging methods didn''t actually do anything, you''d still have the overhead of all these needless method calls throughout your production release. You can''t just delete the class, if you did that you''d have to go through and remove all references to it in all your other code.

Macros entirely occur at the preprocessor level, before the compiler even comes into play. If you turn them off, then they''re not included in your binary at all. assert() is a good example of this.

C++ has reduced the need for macros dramatically, but when it comes to debug code versus production code, macros are still quite useful.
quote:Original post by hellfire
Okay, here is my real question, this guy as far as I can tell, is using macros instead of using objects and inhertance. ( I wish I could post the code, but I can't.) Does anyone think that is okay?
If he's doing code like this:
struct X {  #define X_MEMBERS int blaa; int blee;  X_MEMBERS};struct Y { //derived from X  #define Y_MEMBERS int foo; int bar;  X_MEMBERS  Y_MEMBERS};   

Instead of
struct X {  int blaa;  int blee;};struct Y : X {  int foo;  int bar;};   

Then he's doing something very wrong . But I can't really say since I haven't seen his code.

[edited by - civguy on September 1, 2003 3:58:13 AM]
Yes, he is doing something like that, but much worse and much uglier, and much more confusing. How did you see his code.



quote:Original post by civguy
quote:Original post by hellfire
Okay, here is my real question, this guy as far as I can tell, is using macros instead of using objects and inhertance. ( I wish I could post the code, but I can''t.) Does anyone think that is okay?
If he''s doing code like this:
struct X {  #define X_MEMBERS int blaa; int blee;  X_MEMBERS};struct Y { //derived from X  #define Y_MEMBERS int foo; int bar;  X_MEMBERS  Y_MEMBERS};    

Instead of
struct X {  int blaa;  int blee;};struct Y : X {  int foo;  int bar;};    

Then he''s doing something very wrong . But I can''t really say since I haven''t seen his code.

[edited by - civguy on September 1, 2003 3:58:13 AM]


This topic is closed to new replies.

Advertisement