【问题标题】:Why automatic variable will contain garbage if it is not set?如果未设置,为什么自动变量会包含垃圾?
【发布时间】:2014-08-21 15:30:50
【问题描述】:

在“C 编程语言”第三版和第 32 页中,我看到了让我感到困惑的那些行:

因为自动变量随着函数调用来来去去,它们 不要从一个调用到下一个调用保留它们的值,并且必须 在每个条目上明确设置。如果它们没有设置,它们将包含 垃圾

是说对于下面的代码,a在程序执行完成后不会包含垃圾,如果我这样声明aint a;那么a会包含垃圾?

#include <stdio.h>
int main () {
        int a = 5;
        // int a;
        printf("\n\t %d", a);
}

【问题讨论】:

  • 它不包含垃圾。包含的内容是未定义的。在 Windows 上它可能是 0,但根据 C 语言它可能是飞猴洗碗机。
  • 问题在于它经常会包含0,但并非总是如此。未能初始化其自动变量的程序员会发现它在大多数情况下都能正常工作......这比让它持续失败要糟糕得多。
  • 基本上 i 包含上次执行程序留下的垃圾。
  • @Igor 我没喝醉,但我仍然知道 OP 指的是他代码中的注释部分。
  • @HuStmpHrrr 它不会包含任何现代(多用户,受保护的内存)操作系统上“最后执行的程序留下的”数据。那将是一个巨大的安全漏洞。

标签: c garbage


【解决方案1】:

使用未初始化变量的值是未定义的行为。实际上,自动变量分配在处理器寄存器或堆栈中。通常,如果未初始化,它们将获得当前用于堆栈的寄存器或内存中的值。所以例如int 变量可能包含一部分内存,它是刚才调用的函数中的 double 变量。换句话说,这个值是随机的。

【讨论】:

  • 或者,如果你没有一个无脑编译器,它会是一个寄存器。其中的内容也将是未定义的......
【解决方案2】:

考虑以下示例:

#include <stdio.h>

void fun1(void)
{
    int num1;
    printf("fun1: %i\n", num1);
}

void fun2(void)
{
    int num2 = 7;
    printf("fun2: %i\n", num2);
}

int main(void)
{ 
    fun1();
    fun2();
    fun1();

    return 0;
}

在我的机器上,我得到以下输出:

乐趣1:0
乐趣2:7
乐趣1:7

如您所见,因为num1 未初始化,所以它的值与调用时堆栈中的值相同。

您可以在程序执行期间像这样可视化堆栈:

主要乐趣1 主要乐趣2 主要乐趣1 主要 [0] SP->[0] [0] SP->[7] [7] SP->[7] [7] SP->[x] [x] SP->[x] [x] SP->[x] [x] SP->[x] 图注: SP = 堆栈指针,x = 无关

【讨论】:

    【解决方案3】:

    如果你在使用变量之前没有初始化它,它只会被计算机在变量所在的内存空间中的任何东西填满,这就是为什么最好总是给它们一个初始值,即使它是零。

    【讨论】:

      【解决方案4】:
      1. 自动变量在堆栈上分配。堆栈经常改变它的大小。压入堆栈不会覆盖内存,而只是移动堆栈指针。因此,函数帧(保存的寄存器、本地存储和函数的局部变量)被放置在堆栈上而不是其他帧上,并重叠了一些信息。
      2. 静态和全局变量放在数据段或bss 段中。由于安全原因,此段用零填充。想象一下,您没有用零填充此段。由于计算机不会覆盖内存,因此新程序可以访问在此位置分配的先前程序的信息。
      3. 还有寄存器变量,我们要求编译器将它们放在寄存器中。但不能保证,因为编译器可能会决定用自动变量替换它们。

      【讨论】:

      • C 未指定“自动变量在堆栈上分配”。 C 也没有指定“静态和全局变量放在数据段或 bss 段中。”。存在许多内存模型。
      猜你喜欢
      • 2014-01-29
      • 2015-07-03
      • 1970-01-01
      • 2020-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-13
      • 1970-01-01
      相关资源
      最近更新 更多