I've come across this code, which incidentally my profiler reports as a bottleneck:
#include <stdlib.h>
unsigned long a, b;
// Calculate values for a and b
unsigned long c;
c = abs(a - b);
Does that line do anything more interesting that c = a - b;
? Do either of the options invoke undefined or implementation-defined behaviour, and are there other potential gotchas? Note that the C <stdlib.h>
is included, not <cstdlib>
.
I don't know whether you'd regard it as making sense, but
abs()
applied to an unsigned value can certainly return a value other than the one passed in. That's becauseabs()
takes anint
argument and returns anint
value.For example:
When compiled as C or C++ (using GCC 4.9.1 on Mac OS X 10.10.1 Yosemite), it produces:
If the high bit of the unsigned value is set, then the result of
abs()
is not the value that was passed to the function.The subtraction is merely a distraction; if the result has the most significant bit set, the value returned from
abs()
will be different from the value passed to it.When you compile this code with C++ headers, instead of the C headers shown in the question, then it fails to compile with ambiguous call errors:
Compilation errors:
So, the code in the question only compiles when only the C-style headers are used; it doesn't compile when the C++ headers are used. If you add
<stdlib.h>
as well as<cstdlib>
, there's an additional overload available to make the calls more ambiguous.You can make the code compile if you add (in)appropriate casts to the calls to
abs()
, and the absolute value of a signed quantity can be different from the original signed quantity, which is hardly surprising news:Output:
Moral: Don't use the C headers for which there are C++ equivalents in C++ code; use the C++ headers instead.
No, it doesn't make sense.
If you want the difference, use
or
Unsigned if go below zero would wrap back (effect is similar to adding 2sizeof (unsigned long) * CHAR_BIT)
If you are looking for difference between two numbers, you can write a small template as below
Looking at the declaration of abs inherited from
C
(Because you includedstdlib.h
)And abs in
C++
(fromcmath
)If you notice, both the argument and return type of each function are
signed
. So if you pass an unsigned type to one of these function, implicit conversionunsigned T1 -> signed T2 -> unsigned T1
would take place (whereT1
andT2
may be same andT1
islong
in your case). When you convert an unsigned integral to signed integral, the behavior is implementation dependendent if it can not be represented in a signed type.From 4.7 Integral conversions [conv.integral]
I think when c=a-b is negative, if c is unsigned number, c is not the accurate answer. Using abs to guarantee c is a positive number.