PC何时在if块内部分配静态char*

When does PC allocate static char* inside of if block

本文关键字:分配 静态 char 内部 何时 if PC      更新时间:2023-10-16

如果我有

if (a)
{
    char a[10000]=AllElementsFromBufferA();
    DoSomethingWithA(a);
}
else if (b)
{
    char b[10000]=AllElementsFromBufferB();
    DoSOmethingWithB(b);
}
else if (c)
{
.
.
.
x 70;

PC何时分配?即使它不去这里,也会分配它吗?由于我的代码具有许多IF-S,SELE-S和性能非常重要,因此我不知道我是否应该动态分配或喜欢这样。因为,如果这也耗尽了太多的记忆,那也很糟糕。

谢谢!

编辑1 我放了一些更现实的例子

我所知道的编译器将为所有块范围变量分配空间输入处的所有块变量,无论是否被拿到分支,至少对于小变量(标量,小数组等))。在大多数平台上,搁置堆栈空间只是调整堆栈指针的问题,这是一个相当便宜的操作。此外,我认为除了当地人的空间外,还要搁置一些"划痕"空间的ABIS任务。

我写了以下示例:

#include <stdio.h>
int main( void )
{
  int foo = 0;
  scanf( "%d", &foo );
  if ( foo == 1 )
  {
    char a[10000] = "foo";
    printf( "a = %sn", a );
  }
  else if ( foo == 2 )
  {
    char b[10000] = "bar";
    printf( "b = %sn", b );
  }
  else
  {
    char c[10000] = "bletch";
    printf( "c = %sn", c );
  }
  printf( "donen" );
  return 0;
}

并与GCC(5.3.0,mingw)一起编译如下:

gcc -S alloc.c

给我以下机器代码列表:

        .file   "alloc.c"
        .def    ___main;        .scl    2;      .type   32;     .endef
        .section .rdata,"dr"
LC0:
        .ascii "%d"
LC1:
        .ascii "a = %s12"
LC2:
        .ascii "b = %s12"
LC3:
        .ascii "c = %s12"
LC4:
        .ascii "done"
        .text
        .globl  _main
        .def    _main;  .scl    2;      .type   32;     .endef
_main:
LFB10:
        .cfi_startproc
        pushl   %ebp
        .cfi_def_cfa_offset 8
        .cfi_offset 5, -8
        movl    %esp, %ebp
        .cfi_def_cfa_register 5
        andl    $-16, %esp
        movl    $10032, %eax              // allocate stack space
        call    ___chkstk_ms              // with these three
        subl    %eax, %esp                // instructions
        call    ___main
        movl    $0, 10028(%esp)
        leal    10028(%esp), %eax
        movl    %eax, 4(%esp)
        movl    $LC0, (%esp)
        call    _scanf
        movl    10028(%esp), %eax
        cmpl    $1, %eax                 // if ( foo == 1 )
        jne     L2
        movl    $7303014, 28(%esp)       // a[] = "foo"
        leal    32(%esp), %eax
        movl    $9996, %edx
        movl    %edx, 8(%esp)
        movl    $0, 4(%esp)
        movl    %eax, (%esp)
        call    _memset
        leal    28(%esp), %eax
        movl    %eax, 4(%esp)
        movl    $LC1, (%esp)
        call    _printf
        jmp     L3
L2:
        movl    10028(%esp), %eax
        cmpl    $2, %eax                 // else if ( foo == 2 )
        jne     L4
        movl    $7496034, 28(%esp)       // b[] = "bar"
        leal    32(%esp), %eax
        movl    $9996, %edx
        movl    %edx, 8(%esp)
        movl    $0, 4(%esp)
        movl    %eax, (%esp)
        call    _memset
        leal    28(%esp), %eax
        movl    %eax, 4(%esp)
        movl    $LC2, (%esp)
        call    _printf
        jmp     L3
L4:                                        // else
        movl    $1952803938, 28(%esp)      // c[] = "bletch"
        movl    $26723, 32(%esp)
        leal    36(%esp), %eax
        movl    $9992, %edx
        movl    %edx, 8(%esp)
        movl    $0, 4(%esp)
        movl    %eax, (%esp)
        call    _memset
        leal    28(%esp), %eax
        movl    %eax, 4(%esp)
        movl    $LC3, (%esp)
        call    _printf
L3:
        movl    $LC4, (%esp)
        call    _puts
        movl    $0, %eax
        leave
        .cfi_restore 5
        .cfi_def_cfa 4, 4
        ret
        .cfi_endproc
LFE10:
        .ident  "GCC: (GNU) 5.3.0"
        .def    _scanf; .scl    2;      .type   32;     .endef
        .def    _memset;        .scl    2;      .type   32;     .endef
        .def    _printf;        .scl    2;      .type   32;     .endef
        .def    _puts;  .scl    2;      .type   32;     .endef

所以,海湾合作委员会在这里做了相当聪明的事情。首先,它能够确定您在任何给定时间都只能使abc中的一个之一活跃,因此它并没有尝试为所有这三个分配空间。相反,它为一个实例分配了足够的空间,还有一些划痕空间:

    movl    $10032, %eax
    call    ___chkstk_ms
    subl    %eax, %esp

我假设__chkstk_ms确定是否有足够的堆栈空间适合该请求,如果没有,则会引发异常。

除非采用该特定分支,否则它不会尝试初始化每个实例:

movl    $7303014, 28(%esp) // a[] = "foo"
movl    $7496034, 28(%esp) // b[] = "bar"
movl    $1952803938, 28(%esp) // c[] = "bletch"
movl    $26723, 32(%esp)

不用为字符串文字拨出空间"foo""bar""bletch",而是使用movwmovl指令复制2个和4字节的整数,其位模式与这些字符串的ASCII字符序列相对应。IOW:

   7303014  = 0x006f6f66 == "oof"
   7496034  = 0x00726162 == "rab"
1952803938  = 0x74656c62 == "telb"
     26723  = 0x00006863 == "hc"

请记住,X86是小末日,所以所有内容都呈"向后"。

重要

这是一个一个 compiler 一个一个平台的行为 - 没有理由相信不同的编译器会以相同的方式行事。但是,我的经验使我认为大多数编译器都会尝试对分配空间的分配方式,尤其是对于非常大的物体而言。