abs() failure when using SPI.h and SoftwareSerial.h together

I’ve run into a strange problem when trying to use the abs() function in a sketch that includes both the
SPI and SoftwareSerial libraries (IDE v1.0.1, UnoR3).

With both of those libraries included, feeding a long variable to abs() results in abs() treating the input
like an int and overflowing if the value was greater than 32,767.

The minimal example is as follows:

// Including SPI and SoftwareSerial at the same time
// appears to make the abs() function fail.
#include <SPI.h> 
#include <SoftwareSerial.h>

void setup(void)
{  
  Serial.begin(115200);
}

void loop(void)
{
  long myLong = -35001;
  long myLong2;
  long myLong3;
  Serial.print("myLong: ");
  Serial.println(myLong);
  if (myLong < 0) {
    myLong2 = -myLong;
  }
  Serial.print("myLong * -1: ");
  Serial.println(myLong2);
  myLong3 = abs(myLong);
  Serial.print("abs(myLong): ");
  Serial.println(myLong3);
  while(1); // pause permanently
}

The output I get from that sketch is:
myLong: -35001
myLong * -1: 35001
abs(myLong): 30535

However, if I comment out either the SPI.h or SoftwareSerial.h include (leaving the other intact), the abs() function begins working correctly:
myLong: -35001
myLong * -1: 35001
abs(myLong): 35001

One solution is already present in the code, just replace abs() with an if statement to switch sign when the value of myLong is less than zero. This works fine in every instance.

My question is: can anyone comment on why this behavior with abs() is popping up when using this particular combination of libraries? A quick glance at SoftwareSerial.cpp and SPI.cpp didn’t show anything glaring, but I don’t feel like I know enough to pick out the problem even if it’s staring me in the face.

Arduino defines abs:

(Arduino.h)

// undefine stdlib's abs if encountered
#ifdef abs
#undef abs
#endif

#define abs(x) ((x)>0?(x):-(x))

SoftwareSerial.h undefines abs:

// Arduino 0012 workaround
#undef int
#undef char
#undef long
#undef byte
#undef float
#undef abs
#undef round

Normally, #include <Arduino.h> is inserted before the first line of c code (so after all includes). However, SPI.h includes Arduino.h first, which is then undefined in SoftwareSerial.h

Essentially, abs is defined in several different places as slightly different things.
When it’s a function (not a macro) abs is a function that takes an int. When it’s a macro, it can take anything. Try using labs, which takes a long
http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html#gadb8c83badc195efc1229799391fececc
http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html#gae017047d6d0a688ccb622ff062dcd230

I see, so if I had happened to simply put #include <SoftwareSerial.h> before #include <SPI.h>, I wouldn’t have run into this problem. Either way, it looks like one more reason to just avoid using abs() in my code, and use other methods, as you suggest.

Either way, it looks like one more reason to just avoid using abs() in my code

Or, be sure to explicitly include Arduino.h in your sketch, after all other include files.

That 0012 workaround in SoftwareSerial.h should earn someone an ass kicking. If those symbols cause a problem in 0012, the undef'ing should occur inside a #ifdef/#endif block.

PaulS:

Either way, it looks like one more reason to just avoid using abs() in my code

Or, be sure to explicitly include Arduino.h in your sketch, after all other include files.

Won't work...

#ifndef Arduino_h
#define Arduino_h

...
#endif

As Arduino.h is included at the beginning of the sketch by the IDE, the second (manual) inclusion in your sketch will have no effect whatsoever.

That 0012 workaround in SoftwareSerial.h should earn someone an ass kicking. If those symbols cause a problem in 0012, the undef'ing should occur inside a #ifdef/#endif block.

And some!

As Arduino.h is included at the beginning of the sketch by the IDE, the second (manual) inclusion in your sketch will have no effect whatsoever.

Of course, one could always add a #undef statement...

PaulS:

As Arduino.h is included at the beginning of the sketch by the IDE, the second (manual) inclusion in your sketch will have no effect whatsoever.

Of course, one could always add a #undef statement...

Isn't that the kind of thing that got us into this mess in the first place? :wink:

Isn't that the kind of thing that got us into this mess in the first place?

I guess I left out the part about "tongue firmly in cheek". 8)

PaulS:
I guess I left out the part about "tongue firmly in cheek". 8)

There doesn't seem to be a smiley for that... :%