For example, if I have:
unsigned long int Variable1;
Variable1 = 0xFFFFFFFF;
What would be the value of Variable1? Would it be back to zero?
Yes, and it would set the overflow flag.
also it would become positive not negative.
32-bit math on the CM0 same as CM3/4, etc
If this is written in C, then this behaviour (somewhat surprisingly) follows from the language not the processor, see C99 6.2.5#9:
A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.
Quoting the explanation by Derek Jones:
This behavior describes what most processor operations on unsigned values already do. In those rare caseswhere a processor does not support unsigned operations, calls to internal library functions have to be made.
In your particular case, the result depends on definition of unsigned long int - although probably all existing Cortex-M-targeting compilers define it as 32-bit; a compiler may quite well chose it to be other than 32-bit, and then it would not overflow at this particular case.
I've tested it using Keil and STM32F042 device and the Variable1 goes back to zero. I guess I just want to be sure it is a known and defined operation, not something that can have a random result.
Also, if I have two long unsigned int variables and if I perform subtraction, I would do something like this:
unsigned long int var1, var2;
result = (int)(var1 - var2);
result would be negative if var2 > var1, and positive if var1 > var2.
Even if unsigned long int would be of the same width as int (i.e. both 32-bit in the CortexM world), this can't be guaranteed.
For example, if var1 = 0xFFFFFFFF = +4294967295 and var2 = 0, as var1>var2 you expect the result to be positive, but with probably all compilers the result will be 0xFFFFFFFF which interpreted as int is -1.
Ah ... you're right, but I forgot to mention that since I am only interested in unsigned
arithmetic only, my actual codes are like below:
result = abs((int) (var1 - var2));
so abs ( (int)(0xFFFFFFFF - 0) ) = 1 which is the intended result.
but that was good point.
I guess I should explain why I brought this up in the first place. I need to use a variable to keep track of elapsed time.
I have a 0.5 seconds timer that counts up a variable in this case I use an "unsigned long int". Because of potential
overflow, I want to make sure the arithmetic is correct in case of overflow. All I need is the increment count, not the
actual sign. That is why I use abs().
The abs is unnecessary here, for
volatile uint32_t uwTick.
Start = uwTick;
while((uwTick - Start) < 500); // Works for all values in the uint32_t number space
with abs() you'll fail beyond 0x7FFFFFFF ticks
Well I need a long time elapsed. For example, if I need to keep track of time longer than 30 seconds, does uwTick able to support that?
Yes, if ticking at 1ms the wrap time is a little over 49 days.
Ticking at 72 MHz, around a minute.
Well I'll look into uwTick, but with respect to my method, what would be the outcome?
unsigned long int var1 = 0x7FFFFFFF;
unsigned long int var2 = 0x8FFFFFFF;
int result = abs( (int)(var1 - var2) = ?? I want it to be 0xEFFFFFFF ? will I get this or something else?
int result = abs( (int)(var2 - var1) = 0x10000000 => this is what I want.
Stop using signed types. Use them only when they are REALLY needed. And use <stdint.h> types if you want certain bit width, i.e. uint32_t here.
uint32_t var1 = 0x7FFFFFFF;
uint32_t var2 = 0x8FFFFFFF;
result = var2 - var1; // result == 0x10000000
result = var1 - var2; // result == 0xF0000000
result = var1 - var2 - 1; // result == 0xEFFFFFFF
There is still a possible problem although I don't think it will happen in my code. The counter counts up every 0.5 seconds.
So if I have two events happens at: 0x7FF and 0xFFF for example, then I would have to do this:
uint32_t var1 = 0x7FF;
uint32_t var2 - 0xFFF;
float elapsed_time = 0.5 * (float)(0xFFF - 0x7FF);
so the compiler has to convert uint32_t to float then do the multiplication.
First my program does not need any elapsed time maybe longer than 30 seconds so the situation above (0x7FFFFFFF - 0x8FFFFFFF) won't happen. But theoretically even if I were to use uint32_t, there is still a need to convert to float.
Let's say (var1 - var2) = 0xF000000; How does the compiler handle float arithmetic?
Assuming a non-buggy C-compliant compiler, yes.
Retrieving data ...