Arduino data types: how big each box is
Or see every lesson.
- 455parts on the bench
- 43boards running now
- 1.00xreal time, on every board
Every variable has a type that says what it can hold. On an Arduino Uno, int is 2 bytes and holds -32768 to 32767, long is 4 bytes and holds about plus or minus 2 billion, byte holds 0 to 255, bool holds true or false, char holds one character, and float holds decimals to about seven digits. Pick the type by the biggest number the variable will ever hold.
The circuit above is the code bench, an Uno with three lamps. Press Run and the serial monitor prints each variable the sketch made, then "sizeof(int) = 2" and "sizeof(long) = 4", and last "32000 + 1000 in an int = -32536": an int that went over the top and came around the bottom.
Below is the size of each type on an Uno and an ESP32, the four ways numbers go wrong without an error, and how to turn a float into an int, each run in Mokxi with what it printed.
Want the step-by-step version? The lesson "Variables have a size" walks through this with checkpoints.
Open the lessonThe types, and their sizes
Here are the five variables in the sketch running above, one of each common type. A variable is made by writing its type, a name and, usually, a starting value. char grade = 'A'; uses single quotes, because a char is one character.
The sizes are not the same on every board. We printed sizeof for each type on an Uno and on an ESP32-C3. bool, char and byte were 1 byte on both, and long and float 4 on both. But int was 2 bytes on the Uno and 4 on the ESP32-C3, and double was 4 on the Uno and 8 on the ESP32-C3. A sketch that counts past 32767 in an int works on an ESP32 and goes wrong on an Uno. When the size matters, say it: int16_t, int32_t and uint8_t are the same size everywhere.
byte lampCount = 3;
int blinkMs = 400;
long totalMs = 0;
bool lampsOn = false;
char grade = 'A';When a number does not fit
Nothing stops a number at the top of its type. It wraps around to the bottom, as the sketch above showed with 32000 + 1000 printing -32536. int x = 40000; printed -25536, and the build tab warned: implicit conversion from 'long' to 'int' changes value from 40000 to -25536.
Unsigned types wrap the other way. unsigned int u = 0; minus one printed 65535, and a byte at 255 plus one printed 0. That is why a counter in a byte makes a loop that never ends, and why times from millis() belong in an unsigned long, which lasts 49.7 days before it wraps.
The sum that overflows before it is stored
This one catches people who did pick the right type. long minute = 60 * 1000; printed -5536, even though a long holds 60000 easily. The sum is worked out first, in int because both numbers are ints, and it overflows there; only the wrong answer is put in the long. Clang warned: overflow in expression; result is -5'536 with type 'int'.
Make one of the numbers a long and the whole sum is done in long. 60 * 1000L printed 60000, and 60UL * 60 * 1000 for an hour printed 3600000. Any time a sum of times or sizes could pass 32767, put L or UL on its first number.
void setup() {
Serial.begin(9600);
long minute = 60 * 1000;
Serial.println(minute);
long fixed = 60 * 1000L;
Serial.println(fixed);
unsigned long hour = 60UL * 60 * 1000;
Serial.println(hour);
}
void loop() {
}Whole numbers divide into whole numbers
Divide one int by another and the answer is an int, with the remainder thrown away. 5 / 2 printed 2, and 5 / 2.0 printed 2.50, because one decimal in the sum makes the whole sum decimal. Putting the answer in a float is too late: float half = 5 / 2; printed 2.00, and the average of 3 and 4 came out as 3.00 until it was divided by 2.0.
The version of this everyone writes once is turning a reading into volts. With 3.3 V on A0, analogRead(A0) * (5 / 1023) printed 0.00, because 5 / 1023 is 0 in whole numbers. analogRead(A0) * (5.0 / 1023.0) printed 3.30.
void setup() {
Serial.begin(9600);
Serial.println(5 / 2);
Serial.println(5 / 2.0);
float half = 5 / 2;
Serial.println(half);
float avg = (3 + 4) / 2;
Serial.println(avg);
Serial.println((3 + 4) / 2.0);
}
void loop() {
}float: about seven digits, and never quite exact
A float keeps about seven significant digits and rounds the rest. float big = 123456789; printed 123456792.00, with a warning that the value changed. Decimals are stored in binary, so most of them are slightly off: adding 0.1 ten times printed 1.0000001, and sum == 1.0 was false. Compare floats with a margin, as in abs(sum - 1.0) < 0.001, never with ==.
On an Uno, double is the same 4-byte float, so it does not buy any more digits. One third printed to nine places was 0.333333349 as a double on the Uno and 0.333333333 on the ESP32-C3, where double is 8 bytes.
float to int, and char against byte
Putting a float into an int cuts off the decimals; it does not round. float f = 3.99; stored in an int printed 3, and (int)-3.7 printed -3: toward zero, both ways. To round to the nearest whole number, use round(): round(3.5) printed 4 and round(2.5) printed 3, halves going away from zero. For a positive number, (int)(f + 0.5) does the same and printed 4.
char and byte are both one byte, but they print differently. char c = 65; printed A, because a char is printed as the letter with that code, and byte n = 65; printed 65. A bool prints as 1 or 0.
void setup() {
Serial.begin(9600);
float f = 3.99;
int a = f;
Serial.println(a);
Serial.println((int)-3.7);
Serial.println(round(3.5));
Serial.println((int)round(2.5));
Serial.println((int)(f + 0.5));
}
void loop() {
}Questions
What is the difference between int and long in Arduino?
On an Uno an int is 2 bytes, -32768 to 32767, and a long is 4 bytes, about plus or minus 2.1 billion. On an ESP32 both are 4 bytes. Use long, or unsigned long for millis(), for anything that can pass 32767.
How do I convert a float to an int in Arduino?
Assign it, or write (int)f, and the decimals are cut off: 3.99 becomes 3. Use round(f) to round to the nearest whole number instead.
Why does my Arduino math give a negative number?
The answer went past the top of its type and wrapped round. On an Uno, 32000 + 1000 in an int is -32536, and 60 * 1000 is -5536 even when stored in a long, because the sum is worked out in int. Use long and write 60 * 1000L.
Is double more precise than float on Arduino?
Not on an Uno, Nano or Mega, where double is the same 4-byte float. On an ESP32, a Raspberry Pi Pico or an Uno R4, double is 8 bytes and keeps about 15 digits.
What is the difference between byte and char?
Both are one byte. A byte holds 0 to 255 and prints as a number; a char is meant for a character and prints as a letter, so 65 prints as A.
Keep going
Where the facts on this page come from
Build this for real
Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.