The Core Truth: What Language is Arduino Code?
If you have ever asked, "what language is Arduino code?", the direct answer is C++. However, it is not standard, desktop-oriented C++. Arduino code is a specialized dialect of C++ that relies on a custom core library (the Arduino API), a specific build process, and an underlying toolchain like avr-g++ for legacy boards or xtensa-esp32-elf-g++ for modern ESP32 variants.
Because the Arduino IDE abstracts away the complexities of embedded C++, developers frequently encounter cryptic compilation and linker errors when they attempt to use standard C++ features or write code that conflicts with the IDE's hidden preprocessing steps. In 2026, with the widespread adoption of Arduino IDE 2.3+ and advanced microcontrollers like the ESP32-C6 and Raspberry Pi Pico 2, understanding the exact nature of this language dialect is critical for debugging.
This error fix guide breaks down the most common C++ compilation failures in the Arduino ecosystem and provides actionable, expert-level solutions to resolve them.
Error Fix 1: The 'Not Declared in This Scope' Preprocessor Trap
The Error
error: 'myCustomFunction' was not declared in this scope
The Cause
To understand this error, you must understand how the Arduino IDE processes .ino files. Unlike a standard C++ compiler, the Arduino build system automatically concatenates all .ino tabs, injects #include <Arduino.h> at the top, and attempts to auto-generate function prototypes. According to the Arduino CLI Build Process Documentation, this prototyping engine uses a regex-based parser that frequently fails when functions return complex types, pointers, or use templates.
The Fix
- Manual Prototyping: Add your own function prototype at the very top of your sketch, immediately after the
#includestatements. - Switch to .cpp Tabs: For complex projects, rename your secondary tabs from
.inoto.cpp. The Arduino preprocessor ignores.cppfiles, forcing you to manage your own headers and prototypes, which aligns with standard C++ best practices and eliminates auto-generation errors.
Error Fix 2: Standard C++ Library (STL) and Linker Failures
The Error
undefined reference to `operator new(unsigned int)'
undefined reference to `vtable for std::__cxxabiv1::__si_class_type_info'
The Cause
Many developers assume that because Arduino code is C++, they can freely use the Standard Template Library (STL), exceptions, and Run-Time Type Information (RTTI). However, to conserve precious Flash and SRAM on 8-bit AVR microcontrollers (like the ATmega328P on the Uno R3), the avr-g++ toolchain compiles code with the -fno-exceptions, -fno-rtti, and -fno-threadsafe-statics flags by default. The AVR Libc C++ Support Guide explicitly details how standard C++ features are stripped out to prevent memory bloat.
The Fix
If you are compiling for a modern 32-bit board (like the ESP32-S3 or RP2040) and absolutely require STL features or exceptions, you can override the compiler flags without modifying the core board definitions.
- Navigate to your Arduino core installation directory (e.g.,
~/.arduino15/packages/esp32/hardware/esp32/3.0.x/). - Create a new file named
platform.local.txtin the same folder asplatform.txt. - Add the following line to re-enable exceptions and RTTI:
compiler.cpp.extra_flags=-fexceptions -frtti -std=gnu++17 - Warning: Enabling exceptions on memory-constrained boards can increase your binary size by 10% to 20% and introduce unpredictable heap fragmentation.
Error Fix 3: The Hidden main() and Setup/Loop Conflicts
The Error
multiple definition of `main'
core.a(main.cpp.o): In function `main':
undefined reference to `setup'
undefined reference to `loop'
The Cause
Beginners transitioning from desktop C++ often try to write their own int main() function. The Arduino language abstracts main() away. Under the hood, the Arduino core provides a hidden main.cpp file that initializes the hardware (timers, ADC, USB serial) and calls your setup() once, followed by an infinite while(1) loop that calls your loop() function.
The Fix
Never define main() in an Arduino sketch unless you are writing a bare-metal application and intentionally bypassing the Arduino core. If you need to execute code before setup() runs (such as initializing external watchdog timers or specific memory boundaries), use the GCC constructor attribute:
void preSetupInit() __attribute__((constructor));
void preSetupInit() {
// This runs before main() and setup()
}
Architecture Matrix: C++ Support Across Arduino Cores
Understanding what language features are supported depends heavily on the silicon you are targeting. Below is a comparison of C++ dialect support across popular 2026 Arduino ecosystems.
| Feature | AVR (Uno R3 / Nano) | ARM Cortex-M (Due / Giga) | Xtensa / RISC-V (ESP32 / C6) |
|---|---|---|---|
| Base Language | C++11 (avr-gcc) | C++14/17 (arm-none-eabi-gcc) | C++17/23 (esp-idf v5.x) |
| STL Support | Partial (No std::vector/string) | Full | Full |
| Exceptions | Disabled (Hardware limit) | Disabled by default | Disabled by default |
| Dynamic Allocation | Dangerous (Heap frag.) | Supported | Supported (PSRAM available) |
| Threading | None (Cooperative only) | RTOS / Mbed OS | FreeRTOS (Native) |
Source context derived from the Espressif Arduino-ESP32 Official Documentation and standard ARM embedded toolchain specifications.
Error Fix 4: Memory Exhaustion and Harvard Architecture Errors
The Error
region `data' overflowed by 145 bytes
section `.text' will not fit in region `rom'
The Cause
Standard C++ assumes a Von Neumann architecture where code and data share the same memory space. 8-bit AVR microcontrollers use a Harvard architecture, meaning Flash (program memory) and SRAM (data memory) are strictly separated. If you define large string arrays or lookup tables in standard C++:
const char* myStrings[] = {"Error 1", "Error 2", "System Failure"};
The compiler will place the string literals in SRAM, instantly causing a data overflow error because the ATmega328P only has 2KB of SRAM.
The Fix
You must explicitly instruct the compiler to keep constants in Flash memory using the PROGMEM directive or the Arduino F() macro.
- For Serial Prints: Wrap strings in the
F()macro.Serial.println(F("System initialized successfully.")); - For Arrays: Use
PROGMEMand read viapgm_read_byte()orpgm_read_ptr().const char string_0[] PROGMEM = "Error 1"; const char* const string_table[] PROGMEM = {string_0};
Summary Checklist for Arduino C++ Debugging
When confronted with a wall of red text in the Arduino IDE output console, run through this diagnostic checklist:
- Check the File Extension: Are you using
.ino? If the preprocessor is mangling your templates or pointers, switch to.cppand manage your own headers. - Verify Architecture Limits: Are you trying to use
std::vectorornewon an AVR board? Pivot to statically allocated C-arrays or memory pools. - Inspect Compiler Flags: If using advanced C++17 features on an ESP32, ensure your
platform.local.txtis configured to support the required standard and hasn't been overwritten by a core update. - Isolate Memory Leaks: If the code compiles but reboots randomly (Guru Meditation Error or Watchdog Reset), you are likely fragmenting the heap with standard C++
Stringobjects. Replace them with fixed-sizecharbuffers.
Expert Insight: The Arduino language is ultimately just a C++ API wrapper. The moment you treat it like standard desktop C++, the embedded environment will push back. Mastering the "what language is Arduino code" question means mastering the limitations of the underlying silicon and the GCC toolchain compiling your sketch.






