strange integer substraction

sketch

#define sp Serial.print
#define spln Serial.println

#define WEST_SENSORS 3
#define NORTH_SENSORS 4
#define EST_SENSORS 3
#define SOUTH_SENSORS 3
#define EXT_SENSORS WEST_SENSORS+NORTH_SENSORS+EST_SENSORS+SOUTH_SENSORS
#define MAX_SENSORS 18 // interrupt hw limitation

void setup(){

  Serial.begin(115200);
  while (!Serial);
  sp("max is ");sp(MAX_SENSORS);sp(" ext is ");sp(EXT_SENSORS);sp(" max-ext is ");sp(MAX_SENSORS-EXT_SENSORS); sp(" ext-max is ");
                                   spln(EXT_SENSORS-MAX_SENSORS);
}

void loop(){
;
}

on the console

max is 18 ext is 13 max-ext is 25 ext-max is -5

How come??

MAX_SENSORS-EXT_SENSORS

expands to

MAX_SENSORS-WEST_SENSORS+NORTH_SENSORS+EST_SENSORS+SOUTH_SENSORS

18 - 3 + 4 + 3 + 3

 #define EXT_SENSORS ( WEST_SENSORS+NORTH_SENSORS+EST_SENSORS+SOUTH_SENSORS )

You probably want the extra parens. #define subsititution is just TEXT substitution in the program source, so when an expression from a #define is smacked down next to other math, operator precedence of the whole text expression takes place according to C rules. when you probably want the sum calculated first... This has some famously horrible examples, and you frequently see #define with EXTRA parans "just in case"

#define one (1)

subtle is the (c programmer's) god..

Thanks GypsumFantastic, Thanks Westfw

A good case of "Macro's are dangerous!". And C++ has a lot of tools so you don't have to use macros in a whole lot of cases. As so in this case. It doesn't make the code more readable but it does make it prone to errors.

http://hackaday.com/2015/10/16/code-craft-when-define-is-considered-harmful/

Thank you Septillion

When you are using #define to name a constant, consider using 'const' instead. That would have produced the expected values.

const int WEST_SENSORS = 3;
const int NORTH_SENSORS = 4;
const int EST_SENSORS = 3;
const int SOUTH_SENSORS = 3;
const int EXT_SENSORS = WEST_SENSORS+NORTH_SENSORS+EST_SENSORS+SOUTH_SENSORS;
const int MAX_SENSORS = 18; // interrupt hw limitation

Thanks John but I understand that in this the compiler is free to implement it as a constant in the program or as a variable though in the case of the IDE, as far as I read, it is implemented as a program litteral.

A good rule of thumb with a higher language like C++, don't try to outsmart the compiler. It does a pretty good job optimizing the code.

And in this case, using cont byte results in the same amount of RAM used aka it's smart enough to not reserve RAM for it.

And if it does put it into RAM it has a reason for it :)