• Welcome to Valhalla Legends Archive.
 

Using C++ Macros...

Started by MyndFyre, September 04, 2003, 12:27 PM

Previous topic - Next topic

MyndFyre

Just out of curiousity, why do C++ programmers use macros:

#define MYVALUE 5

instead of using constants:

const int MyValue = 5;


?

Just wondering, thanks!

--Rob
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

Eibro

Quote from: Myndfyre on September 04, 2003, 12:27 PM
Just out of curiousity, why do C++ programmers use macros:

#define MYVALUE 5

instead of using constants:

const int MyValue = 5;


?

Just wondering, thanks!

--Rob
I'd say C++ programmers use constants, and C programmers use #defines. At least, that's how it should be. :) constants have many advantages over preprocessor macros.
Eibro of Yeti Lovers.

Kp

Quote from: Eibro on September 04, 2003, 12:32 PM
Quote from: Myndfyre on September 04, 2003, 12:27 PM
Just out of curiousity, why do C++ programmers use macros:#define MYVALUE 5instead of using constants:
const int MyValue = 5;?
Just wondering, thanks!
--Rob
I'd say C++ programmers use constants, and C programmers use #defines. At least, that's how it should be. :) constants have many advantages over preprocessor macros.
With a const, you can't do something dangerously useful like alias declfn(X) to be static void X (int my1, char *my2, float my3) /* we can change the signatures of all functions declared with declfn just by updating this macro */

I've actually never seen a good argument for a const in place of a preprocessor definition.  The only excuse I can come up with is "type safety", but that seems unlikely - good symbolic constants are explicitly cast in their expansion or are named such that you'd have to be quite inattentive to use it with the wrong type.

Note that using const as a modifier on pointers is very useful, both for documentation that the callee won't tamper and to have the compiler enforce such when the callee is built.
[19:20:23] (BotNet) <[vL]Kp> Any idiot can make a bot with CSB, and many do!

Adron

A good reason to use a const is that you can take its address? Or can you?

Kp

Quote from: Adron on September 04, 2003, 05:36 PM
A good reason to use a const is that you can take its address? Or can you?
My intent (though not stated) was why use a const if you are only defining the value of it for use assigning to other objects?  That is, assuming you don't plan on ever passing its address, what use is there?

I've grown unaccustomed to trying to pass the addresses of true consts because of some problems I had where various Windows functions failed with EFAULT equivalent when they shouldn't have.  Specificially: I requested an operation which would require that it query the value at the address I passed, and do something with it; however, it failed because the OS insisted on having read and write access to the location -- apparently they felt it better to move the check up above whatever dispatcher breaks out read requests from write requests.
[19:20:23] (BotNet) <[vL]Kp> Any idiot can make a bot with CSB, and many do!

Adron

For basic use, a #define is just fine. If you have a set of constants, I like to make them an enum. Sometimes debuggers handle enums better than #define's.

Camel

With a #define macro, the compiler (at least in theory) simply replaces the macro name with the macro content upon (?)precompile. So, this: #define mymacro 5
int main()
{
   return mymacro;
}
should simply be replaced with: int main()
{
   return 5;
}


If the macro is used multiple times, it will appear as multiple (?)constants -- I hesitate to say constants because I'm not sure if the standard is to treat all literal numbers the same way as constants or not.

A constant on the other hand should be the same as a variable, except it is not intended to be modified. I am unaware of the extent to which this is enforced. The idea being that it is stored as one number post-compile.


Anyways, this is just my undererstanding of how consts work; feel free to correct me. :)

MyndFyre

I guess the reason I asked is because I'm starting to play around with Visual C++, and when I go to a definition, I always find macro definitions in the header files rather than const definitions....  For example, I recently had to look up the message number of something or another to scroll a window.  The problem was, I had to prototype the method in C#, and since I couldn't access the API values, I had to explicitly put the correct value into the function call.

So... when using #define, is the value explicitly put into the locations of the macro, whereas a const doesn't?  I'd imagine a smart optimization would explicitly put the values of enums, consts, AND #defines all into the proper place....  I can see from an assembly standpoint where this would make sense....
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

Eibro

#8
When you do something like #define PI 3.14f the symbolic name PI will never be seen by compilers. This would get pretty confusing if the number 3.14 started popping up as part of compile errors. Especially if PI was defined in a file which you didn't write.

Preprocessor defines usually take two forms:
#define SOME_CONSTANT 0xFF
#define SOME_FN(X) (X * X)

The first could be replaced by a type-safe and symbolic const, const unsigned char SOME_CONSTANT = 0xff;
The second, could obviously be replaced by an inline function. inline int SOME_FN(int X) { return X * X; }
Another thing to note is the weirdness of something like:
#define SQUARE(X)  (X * X)
int result = SQUARE(var + some_other_var); // Or other more complex expressions
Eibro of Yeti Lovers.

Kp

Quote from: Eibro on September 04, 2003, 07:44 PM
When you do something like #define PI 3.14f the symbolic name PI will never be seen by compilers. This would get pretty confusing if the number 3.14 started popping up as part of compile errors.
Yes.  That's one thing I hadn't considered - but it shouldn't be a problem if people don't go polluting the namespace with simplisticly named macros. :)

Quote from: Eibro on September 04, 2003, 07:44 PMPreprocessor defines usually take two forms:
#define SOME_CONSTANT 0xFF
#define SOME_FN(X) (X * X)

The first could be replaced by a type-safe and symbolic const, const unsigned char SOME_CONSTANT = 0xff;
Yes.  Or you could #define SOME_CONSTANT ((unsigned char) 0xFF). :)

Quote from: Eibro on September 04, 2003, 07:44 PMThe second, could obviously be replaced by an inline function. inline int SOME_FN(int X) { return X * X; }
Yes.  However, as a minor argument, the inline solution doesn't allow for non-int squaring. :)
Quote from: Eibro on September 04, 2003, 07:44 PMAnother thing to note is the weirdness of something like:
#define SQUARE(X)  (X * X)
int result = SQUARE(var + some_other_var); // Or other more complex expressions

Yes.  That's why you're supposed to be paranoid with parantheses.  #define SQUARE(X) ((X)*(X)).
[19:20:23] (BotNet) <[vL]Kp> Any idiot can make a bot with CSB, and many do!

Eibro

QuoteYes.  Or you could #define SOME_CONSTANT ((unsigned char) 0xFF).
Bah, that's what I meant :)
QuoteYes.  However, as a minor argument, the inline solution doesn't allow for non-int squaring.
This is exactly what templates are for.
QuoteYes.  That's why you're supposed to be paranoid with parantheses.  #define SQUARE(X) ((X)*(X)).
Yes, I suppose anyone that's apt to use macros wouldn't make this mistake anyway.
Eibro of Yeti Lovers.

Adron

#11
Quote from: Kp on September 04, 2003, 08:20 PM
Quote from: Eibro on September 04, 2003, 07:44 PMAnother thing to note is the weirdness of something like:
#define SQUARE(X)  (X * X)
int result = SQUARE(var + some_other_var); // Or other more complex expressions

Yes.  That's why you're supposed to be paranoid with parantheses.  #define SQUARE(X) ((X)*(X)).

You also have to be careful with some expressions. Like, producing the sum of all squares from 1 to 10:


int i = 0, sum = 0;
while(i < 10)
  sum += SQUARE(++i);


For this reason, I prefer inline functions. Summing squares might seem artifical, but if you instead consider doing something with an array element and having a postincrement for the indexing variable you'll have a much more common case.

Kp

Quote from: Eibro on September 04, 2003, 09:15 PMThis is exactly what templates are for.
I hadn't considered templates for inline functions, but that's a very good use for them.  Too bad they don't work in straight C. :p

Quote from: Adron on September 05, 2003, 04:24 AM
Quote from: Kp on September 04, 2003, 08:20 PM
Yes.  That's why you're supposed to be paranoid with parantheses.  #define SQUARE(X) ((X)*(X)).
You also have to be careful with some expressions. Like, producing the sum of all squares from 1 to 10:

int i = 0, sum = 0;
while(i < 10)
  sum += SQUARE(++i);


For this reason, I prefer inline functions. Summing squares might seem artifical, but if you instead consider doing something with an array element and having a postincrement for the indexing variable you'll have a much more common case.
Yes.  I remember both seeing and writing warnings about various macros that if you use the macro, you must not use expressions which have side effects (e.g. pre/post incremenet/decrement) because of exactly the situation you point out.

However, we're getting off topic. :)  The original question was why use a const over a preprocessor macro or vice versa.
[19:20:23] (BotNet) <[vL]Kp> Any idiot can make a bot with CSB, and many do!

Camel

Quote from: Adron on September 05, 2003, 04:24 AM
int i = 0, sum = 0;
while(i < 10)
  sum += SQUARE(++i);

Or, in this case, you could use a for loop.

Eibro

Quote from: Camel on September 05, 2003, 05:50 PM
Quote from: Adron on September 05, 2003, 04:24 AM
int i = 0, sum = 0;
while(i < 10)
  sum += SQUARE(++i);

Or, in this case, you could use a for loop.
Honestly, I don't think Adron knew that.
Obviously, the point of his post was to demonstrate the [sometimes] icky behavior of macros.
Eibro of Yeti Lovers.