Query about using #define directives

Feb 24, 2019 at 6:38pm
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 Feb 24, 2019 at 6:56pm
Feb 24, 2019 at 7:32pm
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
Feb 24, 2019 at 7:34pm
Ohhhh, yeah ... I get it. Okay, that makes sense. Thanks very much indeed! Appreciated.
Feb 25, 2019 at 5:23am
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;


Feb 25, 2019 at 12:16pm
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.
Feb 25, 2019 at 12:21pm
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!
Feb 25, 2019 at 3:11pm
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 
Feb 25, 2019 at 4:42pm
Thanks Peter. I'm going to play around with this stuff some more; it's interesting.
Feb 25, 2019 at 5:34pm
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.
Feb 25, 2019 at 5:41pm
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.
Feb 25, 2019 at 6:27pm
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);
Feb 25, 2019 at 6:38pm
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.
Feb 25, 2019 at 6:48pm
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.