Why Types Matter on a Constrained Chip
On an Arduino Uno you have only 2 KB of SRAM for all your variables, so choosing the right data type is a real engineering decision, not a formality. Each type reserves a fixed amount of memory and defines the range of values it can hold. A variable declaration names a storage location and its type, as in 'int sensorValue = 0;'. Picking a type that is too small causes overflow and wrong readings, while picking one needlessly large wastes precious RAM. Understanding the size and range of each type is fundamental to writing correct, memory-efficient sketches.
Cricket analogy: Choosing a data type is like picking the right sized bat for a player — an oversized bat wastes strength (RAM), while too small a bat can't reach the boundary (overflow), so it must match the batter.
The Core Integer Types
On the 8-bit AVR Uno, a byte and an unsigned char hold 1 byte (0–255), while a char is signed (-128 to 127). An int is 2 bytes and signed (-32,768 to 32,767); its unsigned counterpart, 'unsigned int', spans 0 to 65,535. A long is 4 bytes (about ±2.1 billion) and 'unsigned long' reaches 4,294,967,295 — which is exactly the return type of millis(). Note that int size is board-dependent: on 32-bit boards like the SAMD or ESP32, an int is 4 bytes, so portable code often uses explicit-width types like int16_t or uint32_t.
Cricket analogy: The int range capping at 32,767 is like an old scoreboard with fixed digit wheels — score past its limit and it rolls back to a wrong number, just like integer overflow.
byte pins = 8; // 1 byte, 0-255
int temperature = -5; // 2 bytes on Uno, signed
unsigned int distance = 40000; // 2 bytes, 0-65535
unsigned long startTime; // 4 bytes, matches millis()
float voltage = 3.3; // 4 bytes, ~7 digits precision
bool isReady = false; // 1 byte, true/false
char grade = 'A'; // 1 byte, a single character
void setup() {
startTime = millis(); // millis() returns unsigned long
}
void loop() {}Floats, Booleans, and Characters
A float is a 4-byte number with a decimal point and about 6-7 significant digits of precision; note the AVR has no double — 'double' is treated as float on the Uno. Floating-point math is far slower than integer math because the AVR lacks a hardware floating-point unit, so favour integers where you can. A bool occupies 1 byte and stores true or false. A char stores a single character using its ASCII code, so 'A' is really the number 65. Strings of text are either C-style char arrays terminated by a null, or objects of the String class, which is convenient but can fragment the limited heap.
Cricket analogy: Preferring integers over floats is like choosing a quick single over a risky big shot — floats give precision but cost time, like a slower scoring rate under pressure.
Watch for integer overflow: an unsigned long millis() value wraps back to 0 after about 49.7 days. Always compute elapsed time as 'millis() - startTime' rather than comparing 'millis() > target'; the subtraction handles the wrap correctly, while the direct comparison can fail exactly once per wrap.
Constants and Qualifiers
Use const for values that never change, like a pin number: 'const int ledPin = 9;'. It documents intent and lets the compiler catch accidental writes. The older #define macro also creates constants but performs blind text substitution before compilation and carries no type, so const is generally preferred. The volatile qualifier tells the compiler a variable can change outside normal flow — essential for any variable modified inside an interrupt service routine, otherwise the compiler may cache a stale copy. Choosing the right qualifier is as important as choosing the right type for correct, predictable sketches.
Cricket analogy: const is like a fixed boundary rope that never moves mid-match — everyone relies on it staying put, and any attempt to shift it is flagged as illegal.
Prefer const over #define for constants: const respects scope and type, gives clearer compiler errors, and shows up in the debugger, whereas #define is a raw text replacement that can cause subtle bugs when substituted into unexpected places.
- The Uno has only 2 KB of SRAM, so choosing minimal, correct types matters.
- byte (0–255), int (2 bytes, ±32k on Uno), long/unsigned long (4 bytes) are the core integer types.
- int width is board-dependent; use int16_t/uint32_t for portable code.
- millis() returns unsigned long and wraps after ~49.7 days; use subtraction to measure elapsed time.
- float is 4 bytes with ~7 digits; the Uno has no hardware FPU, so integer math is much faster.
- Use const for fixed values (preferred over #define) and volatile for variables changed inside interrupts.
Practice what you learned
1. How many bytes does an int occupy on an 8-bit Arduino Uno?
2. What is the return type of millis(), and what quirk must you handle?
3. Why is integer math preferred over float math on the Uno?
4. When must a variable be declared volatile?
5. Why is const generally preferred over #define for constants?
Was this page helpful?
You May Also Like
Arduino Sketch Structure
Understand the anatomy of an Arduino sketch: the mandatory setup() and loop() functions, global declarations, comments, and how the program executes from power-on onward.
Your First Blink Sketch
Build and understand the classic Blink program line by line, learn pinMode, digitalWrite, and delay, and see how to make blinking non-blocking with millis().
What Is Arduino?
An introduction to Arduino as an open-source electronics platform combining a programmable microcontroller board with a simple software toolchain for building interactive projects.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics