There is such a sequence of variable declarations inside the function.

{ void *out = NULL; // ... { void *in = NULL; // ... } } 

When the memory for out and in variables is placed on the stack: when does the control go inside the function or when does the control go inside the block separated by curly braces? Do any changes occur to the stack and the variables to be allocated when the block is crossed?

    4 answers 4

    It depends on the compiler and the target platform. In theory, the compiler can always calculate the maximum depth and select everything that is needed in the stack in advance (in the function epilogue, that is, at the input). On the other hand, it can actually increase / decrease the size of the stack when it goes inside a nested block. Of course, the variables from the nested block will not be available to you from the external context.

      Let's look at an example and make volatile variables to eliminate optimizations.

       int main() { volatile char out = 1; { volatile char in = -1; out += in; } return out; } 

      We compile and disassemble (gcc, objdump):

       8048394: 55 push %ebp 8048395: 89 e5 mov %esp,%ebp 8048397: 83 ec 10 sub $0x10,%esp 804839a: c6 45 ff 01 movb $0x1,-0x1(%ebp) 804839e: c6 45 fe ff movb $0xff,-0x2(%ebp) 80483a2: 0f b6 45 ff movzbl -0x1(%ebp),%eax 80483a6: 89 c2 mov %eax,%edx 80483a8: 0f b6 45 fe movzbl -0x2(%ebp),%eax 80483ac: 8d 04 02 lea (%edx,%eax,1),%eax 80483af: 88 45 ff mov %al,-0x1(%ebp) 80483b2: 0f b6 45 ff movzbl -0x1(%ebp),%eax 80483b6: 0f be c0 movsbl %al,%eax 80483b9: c9 leave 80483ba: c3 ret 

      If I’m not mistaken, stack operations are performed when a function is entered, and then it is already used or not used.

        The variable memory on the stack is allocated at the moment of entering the block of curly brackets. Accordingly, when braces are exceeded, all local variables for this block are killed. Although you cannot contact them outside the block. The only nuance is the type design

         for (int i=0;...) {...} 

        which, depending on the compiler and / or its options, can unfold into

         int i; for (i=0;...) {...} // здесь мы можем с i вытворять дальнейшие упражнения :-) 

        or

         ... for (int i=0; ...) {...} // здесь i уже неопределена, т.к. локальна для блока {...} под for 

        I also think that smearing the creation of variables in blocks is not very rational. The downside is: you can easily create two identical different variables and get confused between them.

         ... int i; ... { int i; ... i = 10; // меняем значение "внутренней" i ::i = 10; // меняем значение i из внешнего блока, но при этом если уровней вложенности несколько, то доступ к локальным i из промежуточных блоков, если они там, конечно, есть, теряется. } 

        At the same time, the visibility of the description of variables, which is in pascal (the block of definitions of var), disappears. It is reasonable to locally create objects that should be automatically destroyed. This is useful when using "smart pointers" that automatically kill the target object. And there is no headache - we have freed the memory or not. It is convenient that the object lives strictly where it is needed. Where it is not needed - simply do not turn to it.

        • Just as a comment - in some sources (Straustrup ??? not sure) it is recommended to declare variables in C ++ programs where they are needed for the first time. This contributes to a more efficient allocation of memory by the compiler ... In addition, you will not forget to remove the extra variable if suddenly after changing the code it is no longer needed ... (Although, of course, Visual Studio generates warning'i on unused variables) ... - gote

        In gcc (MinGW) with and without optimization, the stack for both local variables and parameters of called functions is set at the entrance to the function and does not change until it ends.