&符号bug和c的生命周期

时间:2012-05-14 21:24:51

标签: c pointers compiler-warnings local-variables

众所周知,局部变量具有局部范围和生命周期。请考虑以下代码:

      int* abc()
      {
            int m;
            return(&m);
       }
       void main()
       {
             int* p=abc();
             *p=32;
        }

这给了我一个函数返回局部变量地址的警告。 我认为这是理由: 一旦abc()完成,就会释放本地可验证的m。所以我们在主函数中取消引用了无效的内存位置。

但是,请考虑以下代码:

      int* abc()
      {
           int m;
           return(&m);
           int p=9;
       }
       void main()
       {
           int* p=abc();
           *p=32;
       }

我在这里收到同样的警告。但我想m返回时仍会保留其生命周期。怎么了?请解释错误。我的理由是错的吗?

5 个答案:

答案 0 :(得分:10)

首先,请注意永远不会达到int p=9;,因此您的两个版本在功能上是相同的。程序将为m分配内存并返回该内存的地址; return语句下面的任何代码都是不可缓存的。

其次,在函数返回后,实际上并没有取消分配局部变量m。相反,程序会考虑内存可用空间。该空间可能用于其他目的,或者它可能保持未使用状态并永远保持其旧值。因为在abc()函数退出后您无法保证内存会发生什么,所以不应尝试以任何方式访问或修改它。

答案 1 :(得分:8)

一旦遇到return关键字,控制就会传回给调用者,被调用的函数超出范围。因此,所有局部变量都从堆栈中弹出。所以你的第二个例子中的最后一个陈述是无关紧要的,警告是合理的

答案 2 :(得分:3)

逻辑,从函数返回时m不再存在,并且一旦函数退出,对它的任何引用都无效。

物理上,图片有点复杂。 m占用的内存单元肯定仍在那里,如果你在其他任何东西有机会写入之前访问这些单元格,它们将包含在函数中写入它们的值,所以在适当的情况下,您可以在m返回后阅读pabc中存储的内容。 不要依赖这种可重复的行为;这是编码错误

从语言标准(C99):

6.2.4对象的存储持续时间
...
2对象的生存期是存储期间程序执行的一部分 保证为它保留。存在一个对象,具有一个常量地址, 25)并保留 它在其整个生命周期中的最后存储值。 26) 如果一个对象被引用到它的外面 一生,行为是不确定的。当指针变为不确定时,指针的值变得不确定 它指向的对象到达其生命周期的末尾。
25)术语“常量地址”意味着指向对象的两个指针可能不同 时间会比较平等。在两次不同的执行期间,地址可能不同 节目。

26)对于易失性对象,最后一个商店不需要在程序中显式。

强调我的。基本上,你正在做一些语言定义明确地称为未定义行为的东西,这意味着编译器可以自由地以任何方式处理这种情况。它可以发出诊断(您的编译器正在执行),它可以转换代码而无需发出诊断,它可以在此时停止转换等。

答案 3 :(得分:2)

退出函数时,唯一可以使m仍然有效的内存(与代码保持最大相似性)的方法是在前面添加静态关键字

int* abc()
{
           static int m;
           m = 42;
           return &m;
}

返回后的任何事情都是"死分支"那将永远不会被执行。

答案 4 :(得分:-1)

int m应该在本地可见。您应该将其创建为int* m并直接返回。