In the following code, x and y are int32_t variables. In this simplified example, they always differ by 1. When they span the int32_t overflow boundary (0x7FFFFFFF, the max 2's compliment 32-bit positive number, to 0x80000000, the largest magnitude negative number), subtracting them seems to give different results when it is done inside the conditional of the if statement (Method 1) than it does if the result is stored in a temporary variable (Method 2). Why don't they give the same result?
I would think that subtracting two int32_t variables would yield a result of type int32_t, so using a temporary of that type shouldn't change anything. I tried explicitly typecasting inside the if statement conditional; that didn't change anything. FWIW, Method 2 gives the result I would expect.
The code:
int32_t x = (0x80000000 - 3);
int i;
for( i = 0; i < 5; ++i )
{
int32_t y = x + 1; // this may cause rollover from 0x7fffffff (positive) to 0x80000000 (negative)
UARTprintf("\n" "x = 0x%08X, y = 0x%08X", x, y );
if( ( y - x ) >= 1 ) // Method 1
UARTprintf(" - true ");
else
UARTprintf(" - FALSE");
int32_t z = ( y - x ); // Method 2
if( ( z ) >= 1 )
UARTprintf(" - true ");
else
UARTprintf(" - false");
++x;
}
Output:
x = 0x7ffffffd, y = 0x7ffffffe - true - true
x = 0x7ffffffe, y = 0x7fffffff - true - true
x = 0x7fffffff, y = 0x80000000 - FALSE - true
x = 0x80000000, y = 0x80000001 - true - true
x = 0x80000001, y = 0x80000002 - true - true
In my actual application (not this simplified example), y is incremented by a hardware timer and x is a record of when some code was last executed. The test is intended to make some code run at intervals. Considering that y represents time and the application may run for a very long time before it is restarted, just not letting it overflow isn't an option.
Noting, as several of you did, that the standard does not define the behavior when signed integer overflow occurs tells me that I don't have a right to complain that I can't count on it working the way I want it to, but it doesn't give me a solution I can count on. Even using a temporary variable, which seems to work with my current compiler version and settings, might quit working when one of those things changes. Do I have any trustworthy options short of resorting to assembly code?
int32_t)UARTprintfis a macro for a standard printf function, or ultimately doesva_arg(ap, unsigned int))