David Brandorf
David Brandorf

Reputation: 213

Arduino unsigned long overflow

I am trying to understand the overflow conditions for Arduino C++ (specifically the Due/SAM3X8E), in order to write timer logic based on the micros() function.

For those who don't know, the Arduino micros() function returns the number of microseconds which have elapsed since program start, as a 32 bit unsigned long. This value will wrap each 2^32 microseconds (~71 minutes).

The issue is that I am seeing a different result in GCC to what I get on an online arduino simulator.

Here is my test code - first, the GCC version:

#include <stdio.h>

int main()
{
    unsigned long currentTime = 0x00000100;
    unsigned long earlierTime = 0xFFFFFF00;

    unsigned long result = currentTime-earlierTime;

    printf("%lx", result);

    return 0;
}

The above is setup to get the value to overflow by causing a negative number in the result variable, and returns hex ffffffff00000200, as I would expect.

But on Arduino:

// setup
unsigned long currentTime = 0x00000100;
unsigned long earlierTime = 0xFFFFFF00;

// main loop
unsigned long result = currentTime-earlierTime;

Running this on the online arduino sim wokwi returns (hex) 200, which is not expected but is actually more useful to me as my timer checks will still work when the micros() output wraps to zero each 71 minutes.

So my question is: why the difference in behaviour? And can I rely on the behaviour that the online Arduino simulator exhibits to be the same for an Arduino Due (the simulator is based on Uno)? I don't have real Due hardware to test with at the moment.

I hope this question makes sense to someone.

Upvotes: 3

Views: 827

Answers (1)

Adrian McCarthy
Adrian McCarthy

Reputation: 47952

An unsigned long on an Arduino has 32 bits, so the simulator is doing what I would expect an actual Arduino to do.

On desktop PCs, an unsigned long can either have 32 or 64 bits, depending on the operating system, the hardware, and the compiler.

The printf in your gcc test showed a 64-bit value, so on your platform, it appears those unsigned longs have 64 bits. Since that's different than what you'd get on an Arduino, getting a different result is not surprising. Both results look correct and consistent for their respective platforms, so I'm not sure where the confusion lies.

Virtually all C and C++ platforms let you get exactly 32-bit unsigned integers when that's what you want:

  • In C, you include <stdint.h> and use the type uint32_t.
  • In C++, you include <cstdint> and use the type std::uint32_t.

If you modify your code samples accordingly, you should get consistent results whether you're using the code on a desktop or an Arduino (or a simulator).

Upvotes: 3

Related Questions