【问题标题】:C: Loops, conditions, structs in memoryC:内存中的循环、条件、结构
【发布时间】:2015-02-12 13:53:54
【问题描述】:

这个问题可能听起来微不足道,但我知道每当一个函数开始执行时,都会在堆栈中为函数的所有局部变量等创建一个堆栈帧,但我不明白当 for 循环开始执行或if 条件中的代码开始执行。将它们视为在函数的堆栈框架内执行似乎是不合理的,因为它们有自己的范围,因此也有自己的局部变量。但是,它们可以访问它们上面的函数的变量,因此这似乎暗示它们在函数的堆栈框架内。

那么有人可以帮我解决这个问题吗?

它们在执行时实际位于内存中的什么位置?

同样的问题出现在结构上,它们有自己的作用域,它们不是指针,而只是更大的“盒子”,包含整数、char*s 等。

【问题讨论】:

  • 可以合理地认为它们是使用函数的堆栈帧执行的。语句块内可能有额外的变量;实际上,它们是在块的每个条目上分配(并在必要时进行初始化)的。但是如果你在一个循环中有 3 个连续的块,并且每个块都定义了一些变量,那么块 1 中使用的空间很可能会被块 2 和块 3 中的变量重用。

标签: c loops memory struct conditional-statements


【解决方案1】:

循环(或任何其他类似块的构造,例如 if-else 语句)类似于函数。函数是一个自治实体。它本身就是一个完整的计算。当你调用一个函数时,一个函数的指令、语句和表达式只能访问——除了全局变量——函数的局部变量和参数(诀窍是参数可以绑定到调用函数的局部变量、它们的地址等) .

但是,循环、if-else 或任何其他类型的块都是函数的一部分。它不是单独的计算单元。 它们没有被“调用”。它们只是被触及并执行。

块具有范围这一事实并不意味着它们需要单独的堆栈帧。 进入新作用域时不会创建栈帧。 调用函数时会创建栈帧,因为栈与控制流管理有关(例如,栈帧需要保存函数的返回地址)函数。)

是的,嵌套作用域中变量的分配和销毁可以用堆栈来表示,但这不是调用堆栈。这是某种“范围堆栈”,它纯粹是概念性的.让我用一个例子来证明这一点:

void foo()
{
    int a = 42;       // 'a' is declared and is in scope.
                      // Let's pretend its address is 0x1000.

    {
        int b = 1337; // 'b' is declared and in scope.
                      // Let's pretend its address is 0x1004.
    }

    // here, 'b' is destroyed. Nothing is "popped" out of the stack
    // at runtime – it's merely that the compiler can detect that the
    // name 'b' is not in scope anymore. And hence:

    int c = 0; // it may now reuse the former address of 'b', 0x1004,
               // for storing 'c'.
               // Each of these 3 variables reside within the same stack frame.
}

至于结构:这又是完全不同的东西。如果你声明一个结构类型的变量,那么将分配足够大的内存块来按顺序保存结构的所有成员。内存方面,“没有结构”。结构中只有成员,一一分配,正确对齐。 struct 只是一个抽象。

【讨论】:

    【解决方案2】:

    在实际中,变量存在于函数的主栈帧中。您只是不能在声明它的子块之外的任何地方引用它。并不是说每次通过循环都不断地创建和销毁变量。所以更多的问题是编译器允许你通过它的名字来引用它,而不是它的实际存在。

    【讨论】:

    • 请注意,如果块中的自动(局部)变量被初始化,那么该初始化会在块的每个条目上发生。
    • 是的,但是如果它们和上面的函数在同一个栈帧,那么它们里面的变量和上面的函数同名是怎么区分的呢?
    • @Root149:这主要是编译器而不是运行时的问题。编译器始终知道引用了哪个变量,并生成引用正确变量的代码,即使内部语句块中的变量隐藏(隐藏)具有相同名称的全局或文件范围变量,或同名的外部语句块。在汇编器中,变量不是由名称来标识的,而是由堆栈指针的偏移量来标识的。同名的不同变量与堆栈指针的偏移量不同。
    猜你喜欢
    • 2022-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-03
    • 2017-01-09
    • 1970-01-01
    相关资源
    最近更新 更多