作用域块之后堆栈是否被释放?

问题描述 投票:0回答:1

在C/C++中,完成一个作用域块后堆栈上的内存是否被释放并且可以重用吗?

例如,假设进入函数后堆栈上有 100 个空闲字节。

void function(void)
{
    {
        uint8_t buffer1[80];
        // Do something with the buffer
    }
    {
        uint8_t buffer2[80];
        // Do Something with the buffer
    }
}

是否可以为 buffer2 分配足够的内存,还是仅在函数结束时释放用于 buffer1 的内存?

c scope stack
1个回答
0
投票

发生的情况取决于编译器......

  1. 两个缓冲区都可以(单独)放入函数堆栈帧中
  2. 可以将一个区域放入两个块(重新)使用的函数堆栈框架中(例如
    either_buffer[80];
  3. 在每个块的开始,堆栈指针(例如
    sp
    )会递减。缓冲器被作用。堆栈指针递增。

(1)在函数栈帧中分离缓冲区(伪代码):

typedef unsigned char uint8_t;

void do_something(uint8_t *);

uint8_t *sp;

void
function(void)
{
    uint8_t buffer1[80];
    uint8_t buffer2[80];

    {

        // Do something with the buffer
        do_something(buffer1);
    }
    {

        // Do Something with the buffer
        do_something(buffer2);
    }
}

(2)函数栈帧中的单个区域(伪代码):

typedef unsigned char uint8_t;

void do_something(uint8_t *);

uint8_t *sp;

void
function(void)
{
    uint8_t either_buffer[80];

    {
        uint8_t *buffer1 = either_buffer;

        // Do something with the buffer
        do_something(buffer1);
    }
    {
        uint8_t *buffer2 = either_buffer;

        // Do Something with the buffer
        do_something(buffer2);
    }
}

(3)堆栈指针根据需要递增/递减(伪代码):

typedef unsigned char uint8_t;

void do_something(uint8_t *);

uint8_t *sp;

void
function(void)
{
    {
        uint8_t *buffer1 = sp -= 80;

        // Do something with the buffer
        do_something(buffer1);

        sp += 80;
    }
    {
        uint8_t *buffer2 = sp -= 80;

        // Do Something with the buffer
        do_something(buffer2);

        sp += 80;
    }
}

实际发生的情况(对于 x86):

typedef unsigned char uint8_t;

void do_something(uint8_t *);

uint8_t *sp;

void
function(void)
{
    {
        uint8_t buffer1[80];

        // Do something with the buffer
        do_something(buffer1);
    }
    {
        uint8_t buffer2[80];

        // Do Something with the buffer
        do_something(buffer2);
    }
}

这是汇编代码:

    .file   "orig.c"
    .text
    .comm   sp,8,8
    .globl  function
    .type   function, @function
function:
.LFB0:
    .cfi_startproc
    pushq   %rbp    #
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp  #,
    .cfi_def_cfa_register 6
    subq    $80, %rsp   #,
# orig.c:14:        do_something(buffer1);
    leaq    -80(%rbp), %rax #, tmp87
    movq    %rax, %rdi  # tmp87,
    call    do_something    #
# orig.c:20:        do_something(buffer2);
    leaq    -80(%rbp), %rax #, tmp88
    movq    %rax, %rdi  # tmp88,
    call    do_something    #
# orig.c:22: }
    nop
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   function, .-function
    .ident  "GCC: (GNU) 8.3.1 20190223 (Red Hat 8.3.1-2)"
    .section    .note.GNU-stack,"",@progbits

这相当于以下伪代码:

typedef unsigned char uint8_t;

void do_something(uint8_t *);

uint8_t *sp;

void
function(void)
{
    {
        uint8_t *buffer1 = sp - 80;

        // Do something with the buffer
        do_something(buffer1);
    }
    {
        uint8_t *buffer2 = sp - 80;

        // Do Something with the buffer
        do_something(buffer2);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.