Click to See Complete Forum and Search --> : Macros


Gamut
November 25th, 2002, 02:12 PM
can i make a macro return a value ??

something like this..

#define int A_MACRO(X) If (X==1) return 2 \
else return 1;


Thanks in Advance

jfaust
November 25th, 2002, 02:22 PM
No. Macros are not functions. Check this by directly substiting this macro in place where it's used. It's probably not what you want.

You'd be better off avoiding macros altogether, but the following might be more what you want:


#define A_MACRO(X) ((X) == 1 ? 2 : 1)


Jeff

Gamut
November 25th, 2002, 02:29 PM
Thank You Jeff. That was helpful!

willchop
November 25th, 2002, 02:33 PM
If you absolutely had to "return" a value from a macro you can
set one of the macro parameters to a value. As jfaust said,
better to avoid macros if you can. They lack type checking
and can easily produce unintended results.

regards, willchop

KevinHall
November 25th, 2002, 11:36 PM
better off avoiding macros altogether

Hmmm... sounds a bit like "better off avoiding goto altogether!" Personally, I think each has it's place:

Want to jump out of multiple while, for, switch statements? A goto is ok.

Want to hide __LINE__ or __FILE__ inside some statement (like ASSERT() )? Use a macro.

Also... want to use C where templates and inline statements do not exist? Use a macro.

Yes, macros has less typechecking than templates, but as with almost anything... with flexibility comes responsibility.

- Kevin

KevinHall
November 25th, 2002, 11:55 PM
Oh, and you can always do something like this when you need to return the value of some function call that takes place in the middle of your macro -- granted this method requires a global variable, *and I DO recommend you try to find some other way to accomplish what you want* but sometime this makes sense:


#include <stdio.h>

int sq(int x)
{
&nbsp; &nbsp;return x*x;
}

int z;
#define CUBE(x) ( z = x*sq(x), printf("In a macro\n"), 1 ? z : 0 )

void main()
{
&nbsp; &nbsp;printf("3 cubed = %d\n", CUBE(3));
}

The key point is that you need to have:
&nbsp; ",1 ? <return value> : <value that never gets used>"

Hope this helps,

Kevin

jfaust
November 26th, 2002, 12:21 AM
Hmmm... sounds a bit like "better off avoiding goto altogether!"


Well, I won't beat a dead horse except to say... "exactly."

There are rare cases when macros solve a problem better, but there's almost always a better alternative.

Same with goto, although I've seen no example where goto helps anything.

Jeff

KevinHall
November 26th, 2002, 01:06 AM
Consider C, where there is no exception handling:


for ( ; ; )
{
&nbsp; &nbsp;int finished = 0; /* false */

&nbsp; &nbsp;do
&nbsp; &nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp;switch (someCase)
&nbsp; &nbsp; &nbsp; &nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;case 1: finished = 1; /* exit outer loop */
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;break;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;case 2: /* other stuff */
&nbsp; &nbsp; &nbsp; &nbsp;}
&nbsp; &nbsp; &nbsp; &nbsp; if (finished != 0) break;
&nbsp; &nbsp;} while (someCondition);
&nbsp; &nbsp;if (finished != 0) break;
}

OR

for ( ; ; )
{
&nbsp; &nbsp;do
&nbsp; &nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp;switch (someCase)
&nbsp; &nbsp; &nbsp; &nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;case 1: goto outsideLoops; /* exit outer loop */
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;case 2: /* other stuff */
&nbsp; &nbsp; &nbsp; &nbsp;}
&nbsp; &nbsp;} while (someCondition);
}

outsideLoops:

/* continue with program */

KevinHall
November 26th, 2002, 01:22 AM
I should stress that I do recommend avoiding gotos and macros -- if for no other reason because your boss, coworkers, or customers will view your work as unprofessional :) . Seriously, I really have seen this happen. But as I believe (and I know this has been debated many, many times before) that the above example is one place where a goto makes sense. Usually, there is a good reason why something was implemented, and I am weary of saying that it should be *totally* abandonned.

!!!NOTE!!!: I have never found a place in C++ code where goto cannot and should not be replaced (not to say one doesn't exist). goto's are inherently dangerous in C++ because among other things destructors do not get called. In C++ it's very easy to jump out of a block of code while still calling destructors by using try/catch. I have only used gotos in C.

galathaea
November 26th, 2002, 01:44 AM
It seems that every few weeks lately these two issues have popped up. There was a great, impassioned goto thread recently. At the time, I found myself beat by the "goto is not connected to the logic of the branch" argument. However, I have recently doubted that this could be a final argument, since that would mean abandoning break, continue, and generally a goto is just a in-block function call with no parameters and is no more difficult to understand than a true function call except for the lack of return. In fact, this may be one of the unexplored strengths of goto, that it may be used to generalize the function concept in a powerful way, giving one control over the separate tasks of call and return (though this has only occurred to me about a week ago, and I have no real idiom as of yet).

Similarly, with macros, I use them for organizing repetitive tasks like arrays where I want to enforce a naming convention. For example, if I want to make a struct that holds a string "functionname", a function pointer to my own superfunctionname, and some associated members that are named after the original function name, I use a macro because of its string manipulating abilities. Similarly, there are some great uses for macros in automating TypeList declarations and many other uses in "preprocessor metaprogramming" such as that found in the boost libraries.

These are truly debatable issues with much to be sorted out. One point to note, though, is that I believe gotos do call destructors.

galathaea
November 26th, 2002, 01:51 AM
Check out this maelstrom of opinions (http://www.codeguru.com/forum/showthread.php?s=&threadid=214449&highlight=goto) for the battle over goto.

PaulWendt
November 26th, 2002, 06:18 AM
Originally posted by galathaea
These are truly debatable issues with much to be sorted out. One point to note, though, is that I believe gotos do call destructors.

I believe that you are right about this as well. It's my
understanding that nonlocal goto's cause destructors to not be
called ... well at least that's what the standard says about them.
Non-local goto's are created by setjump() & longjump(); the goto
keyword is considered a "local goto".

--Paul

KevinHall
November 26th, 2002, 09:12 AM
Well, I compiled and ran this program below:


#include <iostream>

using namespace std;

struct MyStruct
{
&nbsp; &nbsp;MyStruct() {cout << "In constructor" << endl;}
&nbsp; &nbsp;~MyStruct() {cout << "In destructor" << endl;}
};

void main()
{
&nbsp; &nbsp;int i;

&nbsp; &nbsp;for (i=0;;++i)
&nbsp; &nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp;MyStruct ms;

&nbsp; &nbsp; &nbsp; &nbsp;if (i == 1) goto endMain;
&nbsp; &nbsp;}

endMain:
&nbsp; &nbsp;cout << "Exiting program" << endl;
}


And the constructor does get called (In MSVC6).... I could swear I read somewhere that it didn't. Hmmm....

Paul, C/C++ doesn't allow gotos outside of the currently defined function. If by non-local goto, you mean a longjmp, well there are several issues with that -- only one of them being destructors not being called.

Thanks for helping clear things up!

- Kevin

PaulWendt
November 26th, 2002, 10:16 AM
Originally posted by KevinHall
Paul, C/C++ doesn't allow gotos outside of the currently defined function. If by non-local goto, you mean a longjmp, well there are several issues with that -- only one of them being destructors not being called.


Yeah I meant longjmp(). I'm sorry; I always type them out as
setjump and longjump ... dang unnecessary u's.

JMS
November 26th, 2002, 10:59 AM
*********************************************
There are rare cases when macros solve a problem better, but there's almost always a better alternative.
*********************************************

Macro's are unique in the phylum of C/C++ programming. Anybody who would equate them with const variables is trying to substitute a slice of pizza for an entire pie.

First off const variables can be recast and overwritten which makes them an imperfect alternative when writing libraries for third parties.

Second off and this is a biggie, all would be macro pretenders get interpreted at run time while macro's get interpreted at compile time. This functionality gives programming with macro's incredible functionality, which cannot be replaced with variables.

For example.. The ANSI C/C++ macro’s, which come with all compilers __LINE__ and __FILE__ which respectively return the line number of the calling code file and a string containing the name of the code file. Now if one writes a simple little macro, which puts these, two jewels together...

#define LOG(X) PutItInAFile( (X), __FILE__, __LINE__ )

where

PutItInAFile is a function..

int PutItInAFile( char *pszMsg, char *pszFileName, long lLine);


Now one can put the little macro in one's code like this...


if ( NULL == ( pFoo = new MYFOO))
(
LOG ( "Memory Allocation Failed" );
)


Now your calling log file has not only a timestamp of when an error occurred but also the calling file and the line number of the error. Life without macro's is like a life without color or spice..


**********************************************
your boss, coworkers, or customers will view your work as unprofessional . Seriously, I really have seen this happen.
**********************************************

I know it's true, but it's also true that I've been told the following pearls of wisdom in code reviews....

1- Don't use "void *"'s cause they're ambiguous!!!


2- Either increment loops or decrement loops in your application but don't use both cause they make it hard to read.. Be consistent..

3- Don’t compile your code to find syntax errors, you should be able to eyeball code for that purpose. Since Eastern European software developers make fewer programming and logic errors adhering to this tactic we've actually decided to not provide our developers with compilers!!

Anybody who would tell you that macro's are unprofessional is a person who doesn't understand what they're used for... such absolutism is a totem of mediocrity..

jfaust
November 26th, 2002, 11:18 AM
I don't think anybody's arguing that MACROS don't have their place, but in my experience misuse is more common than correct use. Most macros can be replaced with const variables, typedefs or templates to good effect, reaping the benefits of type safety and debugger friendliness.

When trying to solve a problem, #define is one of the last places you should look. Even so, macros have thier uses, as the examples pointed out in this thread.

Jeff

stober
November 26th, 2002, 12:01 PM
If macros are sooo baaad, then why do all compilers put hundreds of macros in their include files? And every 3d party library that I've seen to the same thing. Just take MSVC6 as an example. My god, there must be several thousand #defines's scattered throughout the include directory. Just a quick search in the include directory shows that 752 files contain the word #define at least once!

Yves M
November 26th, 2002, 12:20 PM
#ifndef _MYHEADER_H_
#define _MYHEADER_H_
//header goes here
#endif // _MYHEADER_H_

;)

And of course, Macros are very useful, since they allow you to maintain the "same" code for different targets. Like Unicode vs. non-Unicode, Debug vs Release etc.

I guess the places where macros should not be used are:

for typedefs (especially those that don't depend on the target for the compilation)
for constant PODs that are actually used. Typechecking might come in handy.
instead of templates if templates would do the job just as well.
instead of inline functions. It's hard to debug and very error-prone.

Paul McKenzie
November 26th, 2002, 01:04 PM
Originally posted by stober
If macros are sooo baaad, then why do all compilers put hundreds of macros in their include files? And every 3d party library that I've seen to the same thing. Just take MSVC6 as an example. My god, there must be several thousand #defines's scattered throughout the include directory. Just a quick search in the include directory shows that 752 files contain the word #define at least once! That is because many of those headers are 'C' headers, not C++ headers. For example <windows.h> and basically *any* API header is a 'C' header. Remember that 'C' programmers also use windows.h and const works differently for C than C++ The responsible thing to do is to use #define.

This is why you see third-party libraries make their headers as generic (i.e. 'C'-like) as possible -- so as not to cause problems to the 'C' programmers out there who may be using their library. You will also notice that the good headers use the 'C' comment structure (/* */) instead of the // comment. Why? Again, because 'C' programmers and 'C' programs still exist, and usage of the // comment may be an error for the C compiler.

Regards,

Paul McKenzie

JMS
November 26th, 2002, 02:19 PM
Paul, there is no C or C++ include file which doesn't also include a wrapper macro which I know of. Likewise there are many macros in VC++ which weren't in MSC way back in the day. The reason is that macro's can be changed at compile time and variables cannot, at least not without macros. Macro's provide compile time logic which variables simple can't. Macros can even be changed even from within MAKE files. These properties make macro's greater than variables even while they are less than in other respectsl. ... I will give you that macro's can be overused, and that the inherent weakness in a lack of type checking makes choosing macros on many tasks suspect.

But to say they can be replaced by const variables or protected class variables is just to stick one's head into the sand and to ignore that macro's compile time resolution gives macros an advantage over const variables which are versatile, advantageous and frankly standard in everything but the most trivial of tasks. To say using macro's is unprofessional ( as someone related second hand, not you ) is just to stand butt naked on one's desk and howl at the moon. It’s hard to take such a statement seriously... The only reasonable argument is in the degree.

KevinHall
November 26th, 2002, 02:22 PM
Anybody who would tell you that macro's are unprofessional is a person who doesn't understand what they're used for... such absolutism is a totem of mediocrity..


True, but unfortunately sometimes those people sign your paychecks. :(

Luckily, I do not currently work for any of these people. :)

Paul McKenzie
November 26th, 2002, 03:24 PM
Originally posted by JMS
Paul, there is no C or C++ include file which doesn't also include a wrapper macro which I know of. Likewise there are many macros in VC++ which weren't in MSC way back in the day. The reason is that macro's can be changed at compile time and variables cannot, at least not without macros. Macro's provide compile time logic which variables simple can't. Macros can even be changed even from within MAKE files. These properties make macro's greater than variables even while they are less than in other respectsl. ... I will give you that macro's can be overused, and that the inherent weakness in a lack of type checking makes choosing macros on many tasks suspect.

But to say they can be replaced by const variables or protected class variables is just to stick one's head into the sand and to ignore that macro's compile time resolution gives macros an advantage over const variables which are versatile, advantageous and frankly standard in everything but the most trivial of tasks. To say using macro's is unprofessional ( as someone related second hand, not you ) is just to stand butt naked on one's desk and howl at the moon. It’s hard to take such a statement seriously... The only reasonable argument is in the degree. I don't think I'm disagreeing too much here. I'm just answering why some header files use #define instead of const.
Backward compatibly with 'C' modules is one reason since const works differently for C than C++. I'm talking strictly about the "simple" #defines, which are probably most of the ones that stober came across when he searched the header files.

It's the same reason why many header files still use "typedef struct" instead of "struct" -- backward compatibility with 'C' modules.

Regards,

Paul McKenzie