-1

I am working on an embedded systems project, so i am dealing with limited memory. I have this huge array of strings in C, it is basically an array of 31 bitmaps. I have it in a separate file called images.c and the header file is images.h, when i include it in main.c file it would take a huge chunk of memory. My question is, if i include the file inside a function and would that array take memory when the function is called? for example

#include <stdio>

void foo(){
   #include "images.h"
   // do stuff with the array of bitmaps
}

int main(){
   //logic to sometimes call foo 
}

would this work? will the array be a local variable in the function and its memory location would be cleared once the function is terminated?

Also am I understanding this correct? I understand that local variables are only local to the scope they are in and cannot be called outside it, but memory wise, is their location in memory actually cleared up? as if they were never there? similar to how a garbage collector works?

6
  • 4
    It will literally paste the content of the file in place of the #include line. So if it will produce any meaningful code, it will compile and do whatever it does. Commented Nov 6, 2024 at 18:58
  • 2
    I recommend to split this into two separate question posts. 1) "What happens if I include a header within a function?" 2) "What effect has defining a huge array of strings within a function, in contrast to outside of a function?" For the second question I recommend to make a minimal reproducible example without any #include. For the first I recommend to make a minimal reproducible example with a a tiny pice of coded inside the header. I recommend to be clearer about the content of images.c, main.c and images.h. I.e. by making actual mres in each case. Commented Nov 6, 2024 at 19:03
  • Either way, I think that the (not trivial) difference will disappoint you. It won't magically decrease the memory needs after all. Bases on improved focus of your question(s) and MREs, your best chances I predict with a surgical use of const and/or de-/compression. Commented Nov 6, 2024 at 19:07
  • 1
    Suggestion: if it's not a header file name it with something other than .h, for example #include "images.dat" or #include "images.inc" Commented Nov 6, 2024 at 19:31
  • @pmg There be dragons. I do not want to put the dangerous idea into words which lies tharrr.... (When is speak-like-a-pirate-day?) Commented Nov 6, 2024 at 19:41

1 Answer 1

1

As far as #include goes, it's a simple substitution of the header file into the C file at compile time. It's no different from pasting the file contents directly into the C file. It has no effect on memory allocation.

Regarding the resulting memory use, in typical implementations:

When the process starts, the initialization data will be part of the text segment of the process. This is usually memory mapped to the executable file, just like the program code, so there's little overhead at that time.

When the function is called, this initialization data will be copied into the stack. So the relevant portion of the file will be paged into RAM, then code similar to memcpy() will copy it to the stack variable.

When the function returns, the stack is unwound.

Putting large arrays in local variables is generally not recommended. The size of the stack segment is usually much more limited than the data segment, where global variables and dynamically-allocated memory are stored. See for example C programming, why does this large array declaration produce a segmentation fault?.

Declaring the array locally might be reasonable if the function is unlikely to be called. But if the function is called repeatedly, it would probably be better to just declare the array as a global, so it only has to be copied into memory once when the program starts. And if it's constant, it will be put into the text segment just like initialization data, and accessing it will simply reference that same memory.

Sign up to request clarification or add additional context in comments.

8 Comments

Declaring the array locally might be reasonable if the function is unlikely to be called. But if the function is called repeatedly, How would that help? Worst case, the compiler emits instructions to materialize the data using mov-immediate or whatever, so the total machine-code size is like 1.5x the size of the data, and you need enough stack space to hold it. More likely, the compiler emits code to allocate stack space and memcpy from an initializer in .rodata.
Best case, the compiler optimizes away the stack space and just uses the .rodata space like if you'd declared it static or static const (at function or global scope). If you declare it static or static const, then putting it at function scope is equivalent for performance to global, otherwise it's potentially a lot worse and can't be better. The .data or .rodata pages have to be part of your process's memory footprint unless you write code that allocates memory and opens a file. .rodata pages will stay clean (backed by the executable file) so can be evicted without page-out.
The OP mentions embedded, which might mean a small enough system that .rodata is in flash, e.g. as part of the freestanding executable that is the firmware if it's not a disk image with an OS. The array data definitely needs to be part of the flash firmware image somewhere (although could be compressed, if you don't mind decompressing it into RAM at load or on the fly when needed). If the flash is memory-mapped with the CPU able to do data loads from it, then just making it const at global scopre, or static const in a function, will avoid RAM.
Right, my "typical implementations" description is oriented towards normal computers, not embedded implementations. I'm frequently caught off-guard by the differences.
My first 2 comments were mostly about the mainstream OS case where a process's pages are memory-mapped, backed by the .text/.rodata and .data segments of the disk file being executed. In both likely cases (global, and local using memcpy to the stack if not const), the data has to be part of the executable and mapped into the process's address-space the whole time. In both cases, pages that haven't been touched might not even have RAM allocated for them. In the global or static const case, parts of the array might remain untouched for whole runs of the program. Unlike with memcpy.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.