In my Arduino projects I use both Arduino types and types defined in the "inttypes.h" file, which #includes stdint.h. So far I've always written code only for the ATmega328P microcontroller (either in the UNO board or "standalone").

To be clear, in this question I'm referring to the following types:

  • "Arduino": char, int, long; byte, word, unsigned long
  • inttypes: int8_t, int16_t, int32_t; uint8_t, uint16_t, uint32_t

  • What is the actual difference between e.g. int and int16_t?
  • Is implicit conversion between corresponding types always possible, or should I avoid it even if the compiler doesn't complain? (quite often in my programs I pass an int16_t as int argument to a function and it always works, but is it good practice to do it, in general?
  • "Arduino": char, int, long; byte, word, unsigned long
  • inttypes: int8_t, int16_t, int32_t; uint8_t, uint16_t, uint32_t

A better classification would be:

  • C and C++: char, int, long, unsigned long
  • "Arduino": byte, word
  • inttypes: int8_t, int16_t, int32_t; uint8_t, uint16_t, uint32_t

I generally avoid the Arduino-specific types, as they are quite non-standard, and do not usually exist outside the Arduino world. As for the other types, just like Michel Keijzers suggests, I use the C types when I do not care much about the exact size. int is guaranteed to be at least 16 bits, but is likely to be 32 bits on a 32-bit architecture. It is a good default type, as it is supposed to be efficiently handled on any architecture. These types allow you to write portable code that automatically selects the "right" integer width for whatever architecture it is been compiled for.

If you care about the exact size, which can often be the case in a memory-constrained environment, use the types from inttypes.h. And do not worry about implicit conversions: as long as both types are wide enough to hold the numbers you need to store, a type conversion, whether implicit or explicit, always preserves the value.


int can be depending on the hardware architecture and is mostly 16 or 32 bit. However, an int16_t is always 16 bit, regardless of the hardware architecture.

It will go wrong when you have a 32 bit architecture (for an int), and you are going to cast it to an int16_t, than you lose the MSB 16 bits. Although I think the compiler will give a warning in this case (so in your case you are ok, but it can prevent a lot of work when you port your code to a 32 bit architecture).

However, all Arduinos have int defined as 16 bit, except the Due and SAMD based boards, see: Arduino reference for int (updated after the comment of per1234 below, thanks for that).

Normally I use integer when I don't care much about the type (and know it will stay under 32768, like for most indices in loops). But if you define a (large) array it's better to use an explicit type, or if you know for sure the value will never be higher than 32768 (int8_t) or nonnegative and 65535 (uint8_t).

Also, for the 'eye' unsigned char for an unsigned 'integer' value upto 255, uint8_t looks better than a 'char' which seems more like a character instead of a value.

  • 1
    "However, all Arduinos have int defined as 16 bit, I think that's even true for the Due's." This is incorrect. See arduino.cc/en/Reference/Int – per1234 Jul 22 '17 at 0:43
  • 1
    @per1234 Thank you, I updated my answer – Michel Keijzers Jul 22 '17 at 1:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.