Everything is done in "sections". Where a section goes depends on its use. What gets put into a section, again, depends on its use.
In general you get two "data" sections - .data and .rodata. .data is stored in RAM and is read-write. .rodata is stored in Flash and is read-only.
Things that are "const" generally end up in .rodata. Literals (string, numeric, etc) also end up in .rodata.
For instance, these would normally be stored in Flash:
const char *foo = "foo";
const int bar = 234;
"baz" (string literal)
These will be stored in RAM:
char foo[10];
int bar;
But then of course, it can be more MCU specific, especially when you get into Harvard (split RAM / Flash address spaces) architecture, where accessing data stored in Flash can be more of a special task and not done as normal variables. For instance, the const char *foo="foo";
would be copied into RAM for easy access during the initialization of the program.
When you allocate a variable of any size within a function, such as:
void func() {
char mybuf[100];
}
the variable will be allocated as part of the stack (or an emulated stack-like system using static variables on MCUs with a limited hardware stack, such as low-end 8-bit PICs). As soon as you return from the function all the stack space is reclaimed.
However, if you allocate it using malloc():
void func() {
char *mybuf = malloc(100);
}
it will be allocated on the heap, and it is your responsibility to reclaim that space using free().
The register
keyword, as in:
int register foo;
will, if a register can be allocated, store the data purely within that allocated register. It will never touch RAM, and consequently it will run faster. However, if a register cannot be allocated (they're all in use in the code) then the register keyword will be ignored and the variable allocated in RAM as per normal. One thing to note:
char register *foo;
That will only hold the pointer to the data in a register, not the data itself. The data itself will still be in RAM.
In general, though, the use of the register
keyword is frowned upon since the compiler's optimizer usually does a better job, and using register
can in fact cause other parts of your code to not be optimized as well and end up more complex than they would otherwise be.