100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Arduino Data Types and Variables

Learn the core Arduino/C++ data types, how much memory each uses on an 8-bit AVR, and how to declare variables and constants correctly to avoid overflow and wasted RAM.

FoundationsBeginner10 min readJul 10, 2026
Analogies

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.

cpp
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

Was this page helpful?

Topics covered

#Programming#ArduinoProgrammingStudyNotes#ArduinoDataTypesAndVariables#Arduino#Data#Types#Variables#StudyNotes#SkillVeris#ExamPrep