assuming two arbitrary timestamps:
uint32_t timestamp1;
uint32_t timestamp2;
Is there a standard conform way to get a signed difference of the two beside the obvious variants of converting into bigger signed type and the rather verbose if-else.
Beforehand it is not known which one is larger, but its known that the difference is not greater than max 20bit, so it will fit into 32 bit signed.
int32_t difference = (int32_t)( (int64_t)timestamp1 - (int64_t)timestamp2 );
This variant has the disadvantage that using 64bit arithmetic may not be supported by hardware and is possible of course only if a larger type exists (what if the timestamp already is 64bit).
The other version
int32_t difference;
if (timestamp1 > timestamp2) {
difference = (int32_t)(timestamp1 - timestamp2);
} else {
difference = - ((int32_t)(timestamp2 - timestamp1));
}
is quite verbose and involves conditional jumps.
That is with
int32_t difference = (int32_t)(timestamp1 - timestamp2);
Is this guaranteed to work from standards perspective?
You can use a union
type pun based on
typedef union
{
int32_t _signed;
uint32_t _unsigned;
} u;
Perform the calculation in unsigned
arithmetic, assign the result to the _unsigned
member, then read the _signed
member of the union
as the result:
u result {._unsigned = timestamp1 - timestamp2};
result._signed; // yields the result
This is portable to any platform that implements the fixed width types upon which we are relying (they don't need to). 2's complement is guaranteed for the signed member and, at the "machine" level, 2's complement signed arithmetic is indistinguishable from unsigned arithmetic. There's no conversion or memcpy
-type overhead here: a good compiler will compile out what's essentially standardese syntactic sugar.
(Note that this is undefined behaviour in C++.)
Bathsheba's answer is correct but for completeness here are two more ways (which happen to work in C++ as well):
uint32_t u_diff = timestamp1 - timestamp2;
int32_t difference;
memcpy(&difference, &u_diff, sizeof difference);
and
uint32_t u_diff = timestamp1 - timestamp2;
int32_t difference = *(int32_t *)&u_diff;
The latter is not a strict aliasing violation because that rule explicitly allows punning between signed and unsigned versions of an integer type.
The suggestion:
int32_t difference = (int32_t)(timestamp1 - timestamp2);
will work on any actual machine that exists and offers the int32_t
type, but technically is not guaranteed by the standard (the result is implementation-defined).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With