12

I am doing embedded programming where saving memory is important.

How much stack space would the following C code occupy at run-time?

if (send_small_message) {
    uint8_t buffer[16000];
    // do something with the buffer
} else {
    uint8_t buffer[32000];
    // do something the with buffer
}

Could some compiler decide to allocate 16000 + 32000 = 48kB stack space for both buffers? Or is it guaranteed that since both buffers will never be used at the same time, the compiler will allocate only 32kB - the size of the larger buffer?

FOLLOW UP QUESTION:

void SendSmallMessage() {
    uint8_t buffer[16000];
    // do something with the buffer
}

void SendLargeMessage() {
    uint8_t buffer[32000];
    // do something with the buffer
}

Can a code compiled by some compiler use 16000 + 32000 bytes at run-time to execute the snippet below:

if (send_small_message) {
   SendSmallMessage(); 
} else {
   SendLargeMessage();
}
mercury0114
  • 1,341
  • 2
  • 15
  • 29
  • 8
    C Standard does not enforce the use of a "stack". Your snippet, depending on quality of compiler, compilation options, etc... can end up using 32 or 48k of memory (stack or something else) – pmg Sep 24 '20 at 13:16
  • In practice this will never be more than 32000 if you apply optimization flags. Still I would solve this situation using macros, because you would probably be recompiling the code for a different device anyway, and that way you have a guaranteed result. –  Sep 24 '20 at 13:18
  • 1
    @para, how would you fix this with macros? In my case, the same device can use both smaller and larger buffers depending on the control flow. – mercury0114 Sep 24 '20 at 13:21
  • 2
    Solve this with sensible program design, not with macros... – Lundin Sep 24 '20 at 13:31
  • 1
    You can check the assembly output of the compiler which will show you what exactly happens. – Jabberwocky Sep 24 '20 at 13:49
  • Are you unable to test this on your target? Maybe add some simple printf's of buffer size. – 2785528 Sep 25 '20 at 22:02

2 Answers2

11

Does the C standard guarantee amount of stack used?

No guarantees whatsoever exist for this. The C standard does not mention concepts like stacks. You can even write C for low level CPUs that completely lack a stack.

The C standard does however guarantee that uint8_t is 1 byte large and that 1 byte is 8 bits on your system (or otherwise uint8_t wouldn't be available).

How much stack space would the following C code occupy at run-time?
Could some compiler decide to allocate 16000 + 32000 = 48kB stack space for both buffers?

System-specific, but also depends on exactly how the function is written and what optimizations that take place. Generally though, real world systems allocate room for as much stack as the function requires, given all possible execution paths. So it is quite likely that many compilers would allocate 16k + 32k.

But who cares, since it doesn't make sense to allocate that large amount of memory on the stack in any known system. Not on high-end, PC-like systems and certainly not on memory-restricted embedded systems. You'll get stack overflows all over the place.

The general rule of thumb in embedded is to never allocate any form of buffers on the stack, but always with static storage duration. On PC-like systems, heap allocation is another option.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • I think I'd replace "quite likely that many compilers" with "possible that some compilers", although I have been fortunate never to encounter a compiler that would do that, so far! – Ian Abbott Sep 24 '20 at 13:46
  • @IanAbbott Modern PC compilers will most definitely optimize it. But if you've worked with various more or less skunky embedded system compilers over the past decades, you will find quite a few that can barely optimize anything. – Lundin Sep 24 '20 at 13:50
  • @Lundin: It can make sense, even in embedded systems. The "advantage" might be the automatic storage duration. where you just use the stack provided instead of either using multiple static buffers just sitting there to be used once, or you use some kind of unions to share them. Our automotive ADAS ECUs have huge data to calculate, like having thousand of radar detections to make up an environmental model for all kinds of functions (ACC, EBA, BSD/LCA .. autonomous driving), In our case of ShortRangeRadar, we have a DSP + R5F and 3.5MB for Code&Data together, you count on any byte here. – kesselhaus Sep 25 '20 at 21:03
  • > _The C standard does however guarantee that uint8_t is 1 byte large._ Are you sure about this one? I read somewhere that says that these types are optional but minimum and fastest width types are required https://stackoverflow.com/questions/3200954/what-is-char-bit#comment3299949_3200969 – pratikpc Sep 26 '20 at 18:59
  • @pratikpc Yes it is optional so if a system doesn't have 8 bit bytes, it will not have `uint8_t`. Exotic, obsolete DSPs with other byte sizes than 8 being the only kinds that don't have it. – Lundin Sep 26 '20 at 22:36
5

@Lundin provided an excellent answer. But I wanted to answer from a slightly different perspective.

The C standard basically guarantees behavior of the code. It does not guarantee much of how it is done. It is possible (don't know how likely) that it will even move the buffer declaration outside the if statement. It may also allocate more memory than specified. It is also allowed to allocate less if it does not break anything. Typically, unused variables are removed by the optimizer. The optimizer also often inline small functions instead of calling them, and it may change a printf("\n") to a puts(""). The compiler is free to do anything as long as the observable behavior of the code remains the same.

So no, you don't have any guarantees in this case.

But one thing to consider here. You want to declare a different sized buffer depending on an if statement. Let's say that these extra 16kB would invoke a stack overflow. What do you do if you have less than 32kB of stack left and the else branch needs to be executed? Of course it depends on how the code is used in reality, but it is definitely worth considering. To me, this is a pretty strong code smell.

klutt
  • 30,332
  • 17
  • 55
  • 95