Strings on ESP32 and RPi Pico

Hi !

I am new to this Arduino framework and C++. I used before only Python on RPi Pico and ruined my projects with memory fragmentation. I decided to go “raw” in C++ with Arduino framework. For start, I want to understand how strings are handled in this framework.

I asked 4 AI’s and the answers are contradictory. So I want to ask real humans that really knows how things ar going, if strings defined with const char are stored by default in Flash memory, on ESP32 and RPi Pico family (I'm only interested in exactly these 2 boards!), and they are not loaded in RAM untill they are needed ?

Thanks !

if you write

const char message[] = "Hello World, I'm in flash memory";

or

const char * message = "Hello World, I'm also in flash memory";

In both cases the string literal itself resides in flash memory because it is const which also enforces immutability, and there’s no need for special handling (PROGMEM) like on AVR.

In the first case, const char message[] , the compiler also creates a symbol in RAM for the array variable, but the contents are still in flash, so accessing message reads from flash.

In the second case, const char* message , the pointer variable message is in RAM, pointing directly to the flash-resident string.

➜ The difference is that in the first case the array name behaves like an array with a fixed size, while in the second case it’s just a pointer. (types matter in C++)

I defined 2 strings like this:

const char* Marus1 = "Mesaj Marus 1";
const char Marus2[] = "Mesaj Marus 2";

I use both in setup() so that the compiler doesn't eliminate them through optimization.

And in Inspect it looks like this:

Marus1 STT_OBJECT STB_GLOBAL 0x3FFBDB94 .dram0.data 4 bytes

Marus2 STT_OBJECT STB_LOCAL 0x3F403A78 .flash.rodata 14 bytes

It seems that the one deined as array, Marus2, doesn’t use any RAM at all… But you said: “the compiler also creates a symbol in RAM for the array variable”…

Local scope only , so you don't want to use them on loop().
Leo..

What you are seeing is the difference between a pointer variable (const char*) and an array (const char[]) in the ELF symbol table generated for the ESP32.

const char* Marus1 = "Mesaj Marus 1";
Here, "Mesaj Marus 1" is a string literal. The compiler places it in .flash.rodata (read-only data in flash). But Marus1 itself is just a pointer variable that lives in RAM. That’s why Inspect shows it in .dram0.data at address 0x3FFBDB94 with size 4 bytes (a 32-bit pointer). The pointer’s value is the flash address of the literal.

const char Marus2[] = "Mesaj Marus 2";
Here, Marus2 is defined as a real array. The compiler emits storage for the array itself. The array contents (the characters plus the null terminator) are placed directly into .flash.rodata at 0x3F403A78, with a size of 14 bytes. There is no separate RAM variable; the symbol Marus2 refers directly to that address in flash.

So the key difference is:

➜ With const char*, the literal is in flash, but the pointer variable lives in RAM.
➜ With const char[], the array contents themselves live in flash, and no RAM is used to store a pointer.

1 Like