Arduino - Data Types
Arduino - Data Types in Modern C++
Section titled “Arduino - Data Types in Modern C++”When you program an Arduino, you’re primarily writing in C++. Data types are a fundamental concept in C++ for declaring variables and functions. The type of a variable determines its size in memory and how the stored bits are interpreted. Choosing the right data type is crucial on memory-constrained microcontrollers like an Arduino.
This guide covers the essential data types for Arduino development, updated with modern best practices.
Core Data Types Overview
Section titled “Core Data Types Overview”Here is a summary of the fundamental data types available in the Arduino environment:
| Type | Size (on Uno/AVR) | Range / Description |
|---|---|---|
| boolean | 1 byte | Stores true or false. |
| byte | 1 byte | Stores an unsigned number from 0 to 255. |
| char | 1 byte | Stores a character or a small integer from -128 to 127. |
| unsigned char | 1 byte | Stores an unsigned number from 0 to 255 (same as byte). |
| int | 2 bytes | Stores an integer from -32,768 to 32,767. |
| unsigned int | 2 bytes | Stores an unsigned integer from 0 to 65,535. |
| long | 4 bytes | Stores a large integer from -2,147,483,648 to 2,147,483,647. |
| unsigned long | 4 bytes | Stores a large unsigned integer from 0 to 4,294,967,295. |
| float | 4 bytes | Stores a single-precision floating-point number. |
| double | 4 bytes | Same as float on AVR-based boards (Uno, Mega). 8 bytes on modern ARM boards (Due, Portenta). |
| void | N/A | Used to indicate that a function returns no value. |
A Deeper Look at Key Types
Section titled “A Deeper Look at Key Types”The void keyword is used exclusively in function declarations to specify that the function does not return any value. The built-in setup() and loop() functions are classic examples.
void setup() { // This function runs once and returns nothing.}boolean
Section titled “boolean”A boolean holds one of two values: true or false. It’s perfect for tracking states, like whether an LED is on or off. It occupies one byte of memory.
const int ledPin = 13;boolean isLedOn = false;
void setup() { pinMode(ledPin, OUTPUT);}
void loop() { if (isLedOn) { digitalWrite(ledPin, LOW); isLedOn = false; } else { digitalWrite(ledPin, HIGH); isLedOn = true; } delay(1000);}char and Arithmetic
Section titled “char and Arithmetic”A char stores a character value using one byte of memory. Character literals are enclosed in single quotes (e.g., 'A'). Internally, characters are stored as numbers according to the ASCII table. This allows for arithmetic operations on them.
// 'A' has an ASCII value of 65.char myChar = 'A';
// This will result in the character 'C', which has an ASCII value of 67.char nextChar = myChar + 2;
Serial.print(nextChar); // Prints "C"Best Practice: Fixed-Width Integers
Section titled “Best Practice: Fixed-Width Integers”A common issue in embedded systems is that the size of int can vary between architectures (e.g., 2 bytes on an Arduino Uno, 4 bytes on an Arduino Due). This can lead to unexpected behavior when porting code.
To avoid this, modern C++ practice encourages using fixed-width integers from the <stdint.h> header. These types declare their size explicitly.
int8_t/uint8_t: 8-bit signed/unsigned integer (equivalent tocharandbyte).int16_t/uint16_t: 16-bit signed/unsigned integer (equivalent tointon Uno).int32_t/uint32_t: 32-bit signed/unsigned integer (equivalent tolong).int64_t/uint64_t: 64-bit signed/unsigned integer.
#include <stdint.h>
// This variable will be 16 bits on ANY Arduino board.uint16_t sensorValue = 1023;Strings: The String Object vs. C-style char Arrays
Section titled “Strings: The String Object vs. C-style char Arrays”Handling text in Arduino can be done in two ways, each with significant trade-offs.
1. C-style strings (char arrays)
Section titled “1. C-style strings (char arrays)”This is the traditional, memory-efficient way. A string is an array of characters ending with a null terminator ('\0'). They are fast and don’t cause memory fragmentation, but can be more complex to manipulate.
char message[16] = "Hello, world!"; // Array of 16 chars, 15 for text, 1 for null terminator.Serial.println(message);2. The Arduino String Object
Section titled “2. The Arduino String Object”The String object provides easy-to-use methods for text manipulation (concatenation, searching, etc.). However, it uses dynamic memory allocation. On small microcontrollers, frequent creation and destruction of String objects can lead to heap fragmentation, eventually causing your program to crash unpredictably.
String message = "Hello, ";String name = "Arduino";
// Easy to concatenate, but uses dynamic memory behind the scenes.String greeting = message + name;Serial.println(greeting);Recommendation
Section titled “Recommendation”For small, stable sketches, the String object can be convenient. For any large, long-running, or mission-critical application, it is strongly recommended to use C-style char arrays to avoid memory issues.
Composite and User-Defined Types
Section titled “Composite and User-Defined Types”Arrays
Section titled “Arrays”An array is a collection of variables of the same type.
int sensorReadings[5]; // An array to hold 5 integer readings.sensorReadings[0] = analogRead(A0);sensorReadings[1] = analogRead(A1);Structs
Section titled “Structs”A struct allows you to group different data types into a single, user-defined type. This is incredibly useful for organizing related data.
struct SensorData { int id; float temperature; float humidity; boolean isActive;};
void setup() { Serial.begin(9600);
SensorData livingRoomSensor; livingRoomSensor.id = 1; livingRoomSensor.temperature = 22.5; livingRoomSensor.humidity = 45.8; livingRoomSensor.isActive = true;
Serial.print("Sensor ID: "); Serial.println(livingRoomSensor.id); Serial.print("Temperature: "); Serial.println(livingRoomSensor.temperature);}Common Errors and Debugging
Section titled “Common Errors and Debugging”- Integer Overflow: Assigning a value to a numeric variable that is outside its range. For example,
int count = 40000;will overflow and result in a negative number. Use a larger type likeunsigned intorlong. - Signed/Unsigned Mismatch: Performing arithmetic with both signed and unsigned numbers can lead to unexpected results, especially during comparisons.
- Floating Point Imprecision:
floatanddoubleare approximations. Don’t use==to compare them directly. Instead, check if the absolute difference is within a small tolerance:if (abs(a - b) < 0.001) { ... }.