【问题标题】:Why is a non-static variable in a function being initialized to 0 and why is it becoming static?为什么函数中的非静态变量被初始化为 0,为什么它变成静态的?
【发布时间】:2016-12-14 23:32:09
【问题描述】:

我正在尝试运行以下 C 代码

#include <stdio.h>

void myFunc() {
    static int a;
    int b;
    a++;
    b = b + 2;
    printf("a:%d, b:%d\n",a,b);
}

int main(void)  {
    myFunc();
    myFunc();
    return 0;
}

我在 ubuntu 上使用 gcc 版本 5.4.0 20160609 编译时得到的结果是

a:1, b:2
a:2, b:4

我知道 a 是静态的,将被零初始化,但似乎非静态 b 也被零初始化。此外,看起来 b 实际上正在被转换为静态变量,因为它的值会在第二次调用 myFunc 时保留。

我假设这与我的编译器/操作系统有关,因为使用 codepad 在线编译(使用 gcc 4.1.2)给出了

a:1, b:2
a:2, b:2

虽然出于某种原因仍将 b 初始化为零,但不会为后续调用 myFunc 保留 b 的值。

1) 为什么非静态变量被零初始化?我是不是一直很幸运编译器为它分配了一个被归零的内存块?

2) 为什么 gcc 似乎将 b 转换为 gcc 4 中的静态变量而不是 gcc 5?

编辑:

为了更好地说明这个问题,如果我再添加 6 个对 myFunc 的调用,结果输出是:

a:1, b:2
a:2, b:4
a:3, b:6
a:4, b:8
a:5, b:10
a:6, b:12
a:7, b:14
a:8, b:16

【问题讨论】:

  • 未定义行为未定义...
  • 尝试在对myFunc() 的两次调用之间添加另一个(不同的)函数并在该函数中创建新变量...看看会发生什么。但是,就像@John3136 所说...
  • @Al Kenny:您如何区分真正的零初始化变量和恰好具有垃圾值 0 的垃圾变量?以及如何区分在调用(静态)之间真正保留其值的变量和恰好偶然匹配其先前值的垃圾变量?
  • "为什么非静态变量被零初始化?"这是不确定的。编译器看到类似int b; b = b + 2; printf("b:%d\n",b); 的代码,可以将其替换为puts("b:2"):destroy_hard_drive()。两者都可以,因为它是 未定义的行为
  • 内存位置在栈上。由于您是从同一个父函数调用它们,因此每次都使用相同的堆栈内存,并且在调用之间不会覆盖它。

标签: c variables gcc static non-static


【解决方案1】:
  1. 您的非静态变量 b 未进行零初始化。在您的实验中,b 中的不确定垃圾值恰好为零。零与任何其他值一样垃圾。

  2. 变量b 未“转换为静态”。它在调用之间不保留其值。在您的实验中,恰好在第二次函数调用中b 的不确定垃圾值与第一次调用中的最后一个值相同。该值与任何其他值一样垃圾。

虽然您观察到的“意外”行为有相当简单且确定性的潜在原因,但它是脆弱的。这些都不适用于现实生活中的代码。

【讨论】:

  • 多次运行 myFunc 似乎显示的结果与您所说的相反。如果我修改主代码块调用 myFunc 8 次,我得到输出:a:1, b:2a:2, b:4a:3, b:6a:4, b:8a:5, b:10a:6, b:12a:7, b:14a:8, b:16
  • @keaek 尝试在调用 myFunc() 之间调用其他函数。你看到的原因是因为没有其他东西在使用堆栈的那部分,所以它仍然有上一次调用留下的东西。
  • @Barmar 这解决了一些问题。如果我添加函数void print_something() { printf("something\n"); } 并在调用myFunc() 之间调用它,我会得到类似a:1, b:2 something a:2, b:2 something a:3, b:2 something a:4, b:2 something a:5, b:2 something
  • @keaek:它并没有真正“反击”它。这仅仅意味着您在超洁净的实验室条件(无风无声)中继续故意、成功(且毫无意义地)平衡上翘的埃菲尔铁塔顶端。只需尝试在您的通话之间拨打其他电话,它就会分崩离析并崩溃。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-12-23
  • 1970-01-01
  • 2017-12-07
  • 1970-01-01
  • 2012-02-01
  • 1970-01-01
  • 2015-09-06
相关资源
最近更新 更多