何时在C中初始化局部变量?

时间:2019-03-27 09:04:26

标签: c

请考虑以下示例

purge

我在rvm块中有一个大数组声明。该数组的初始化应花费一些时间。我的问题是:如果是void func(int i){ if(i) { int arr[2048] = {0}; //Doing something related to arr; } else { //Doing something } } ,此数组是否会初始化?

3 个答案:

答案 0 :(得分:6)

  

如果i == 0,该数组是否会初始化?

因为您的代码是

if(i) {
  int arr[2048] = {0};
  //Doing something related to arr;
} else {
  //Doing something
}

如果i==0不存在该数组,则无法对其进行初始化,该数组仅存在于 if 的分支中,其中i != 0

答案 1 :(得分:3)

要了解编译器的行为,您应该考虑在C语言中每个变量都有一个存储类 ISO / IEC 9899:201x§6.2.4对象的存储持续时间)来表征其行为及其“ 寿命”,这意味着该对象的存在(变量是一个对象)以及对其的合法访问条件。 存储类有4种:静态,线程,自动和分配。后者使用动态内存分配。

在您的情况下,数组arr[2048]自动对象,其生存期定义为(在标准@点6的同一段落中):

  

对于这样一个没有可变长度数组类型的对象,   它的生命周期从进入它所在的块开始   关联,直到该块的执行以任何方式结束。 (输入   封闭的块或调用函数将挂起,但不会结束,   执行当前块。)

     

如果以递归方式输入该块,则该对象的新实例为   每次都创建。

     

对象的初始值不确定

     

如果为该对象指定了初始化,则每次初始化   在执行中到达声明或复合文字的时间   的;否则,每次   到达声明。

这说明:

  1. 对象的寿命始于定义对象的块的开头。
  2. 初始值(在我们的例子中为数组内容)是不确定的:编译器不会初始化内存区域。并且指定了初始化后,当执行到达代码段时完成。

第一点很明确,已经是您问题的答案。您引用的代码是:

{    //Block init
  int arr[2048] = {0};
  //Doing something related to arr;
}    // block end

如果您没有输入对象的寿命块,则数组不会开始:该数组不存在。当然,在这种情况下,即使是初始化也不能对对象执行任何操作。

现在,要点2 有助于更好地进行说明。表达式:

int arr[2048] = {0};

由于数组对象的存储类,编译器在功能上未将其解释为带有对象初始化的声明。此外,基本上,它还被视为声明加上赋值

有什么区别?

使用对用户代码透明的机制,在BSS节中静态分配值或使用属于编译器序言和结语的代码来实现具有不同于自动存储类别的初始化变量的声明即使没有访问该对象。

在另一种情况下,初始化代码,赋值是用户代码的一部分,因此,按照执行流程逻辑执行。

这是官方行为。在幕后检查,您会发现在某些情况下,自动变量的空间恰好是从对象生命周期开始就预先分配的,但是这些行为严格取决于CPU体系结构,并且基本上在发生这种情况时不会在功能之间产生差异该代码是语言标准(这是兼容编译器的基本属性)。

答案 2 :(得分:0)

实际上,变量将在使用前初始化 ,无论其是否位于内部作用域中。这段代码:

void func1 (int i){
  if(i) {
    int arr[2048] = {0};
    printf("%d", arr[666]);
  } else {
    //Doing something
  }
}

给出与该代码完全相同的机器代码:

void func2 (int i){
  int arr[2048] = {0};
  if(i) {
    printf("%d", arr[666]);
  } else {
    //Doing something
  }
}

x86上的gcc -O3给出:

.LC0:
        .string "%d"
func1:
        test    edi, edi
        jne     .L4
        ret
.L4:
        xor     esi, esi
        mov     edi, OFFSET FLAT:.LC0
        xor     eax, eax
        jmp     printf

.LC0:
        .string "%d"
func2:
        test    edi, edi
        jne     .L7
        ret
.L7:
        xor     esi, esi
        mov     edi, OFFSET FLAT:.LC0
        xor     eax, eax
        jmp     printf

如您所见,它们是相同的。

虽然最好尽可能限制变量的范围,但这与性能无关。