Query about using #define directives

I realize the method below maybe isn't how one would usually go about setting up #define directives, but I'm wondering why I get the results I do:

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>

int main()
{
#define    ALPHA    2+42
#define    BETA     ALPHA*2

std::cout << ALPHA << std::endl;
std::cout << BETA << std::endl;

return 0;
}

44
86

How come 86 when I do it that way, but when I do it as follows ...

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>

int main()
{
#define    ALPHA    (2+42)
#define    BETA     ALPHA*2

std::cout << ALPHA << std::endl;
std::cout << BETA << std::endl;

return 0;
}

44
88

I'm probably missing something really simple, but any explanations appreciated. Thanks!
Last edited on
It has to do with order of operations... If you don't surround the 2+42 with the (), when translated, it is just 2+42*2 which is 86

But if you surround with (), then it's (2+42)*2 = 88
Ohhhh, yeah ... I get it. Okay, that makes sense. Thanks very much indeed! Appreciated.
You really shouldn't be using #defines for this purpose in a C++ program.

Try it with
1
2
const int ALPHA    2+42;
const int BETA     ALPHA*2;


Hi Salem,

I'm not ... It was just part of a course I'm doing, and I was just playing around with the example code which they'd provided.

It was actually pointing out one or two reasons not to use #defines, before moving on to enumerated types.

Thanks for your comment though.
It's an example of your infamous PEDMAS/BODMAS/BEDMAS miscalculation
https://en.wikipedia.org/wiki/Order_of_operations

Always take care of your order of operations!
The tricky part here is not the order of operations, but the way that macros are expanded. It's easy to make these sort of mistakes even when you know what is going on.

1
2
3
4
#define MAX(x, y) x > y ? x : y // bad
#define MAX(x, y) (x > y ? x : y) // less bad
#define MAX(x, y) ((x) > (y) ? (x) : (y)) // better, but still not good if x and y have 
                                          // side-effects or are expensive to evaluate 
Thanks Peter. I'm going to play around with this stuff some more; it's interesting.
Unless you have to for the aforementioned course, I would avoid using function-like macro and almost all other macros as well (except for ones needed for #includes, and other versioning/OS stuff).

It's a C relic that really just doesn't belong in C++. Just use const variables, and functions.
closed account (E0p9LyTq)
Macro defines are not type-safe. If your macro expects a number and you use not-a-number potentially you could crash the program.
FurryGuy: Not even close. A macro is just a source text replacement. If a macro is written with a certain kind of parameter in mind and the user passes a different kind, all that will happen is that the program will fail to compile, or at worst will be incorrect.
1
2
3
4
5
6
7
8
9
#define APPEND_FIVE(s) ((s) += '5')

//...
std::string s;
APPEND_FIVE(s);
int n = 0;
APPEND_FIVE(n);
std::function<void()> f;
APPEND_FIVE(f);
closed account (E0p9LyTq)
A macro is just a source text replacement.

I do understand that, hands down no question. That is why I said potentially crash the program if it does compile. Array indexing for instance.

A char, 'a' for example, being interpreted as a number when used in a macro that indexes an array/container.

It happened to me with an older compiler, and was a PAIN to figure out.
That has nothing to do with it being not type-checked, though. You can overflow buffers with functions just as easily.
1
2
std::vector<int> v({1});
v.push_back(v['0']);
Topic archived. No new replies allowed.