【问题标题】:Memory and Scope of variable in cc中变量的内存和范围
【发布时间】:2013-07-09 18:57:26
【问题描述】:

您好,谁能告诉我将变量保留在内存中还是立即销毁。

#include <stdio.h> 

int main()
{
    {
        int a=1;
        lab:
        printf("Value of a : %d",a);  
    }   

    return 0;
}

int a 是否会留在内存中?

【问题讨论】:

  • 这取决于实际的实现。但是,它的作用域已结束,因此您无法再访问它,并且编译器可能(并且很可能会)选择将其后备内存用于另一个变量。
  • 哦,还有 int main()...
  • @碳酸先生; +google_plex。我们看到了多少次 void main()!
  • @Bathsheba 我认为人们投射malloc() 的返回值的次数是我们看到的一半。
  • @H2CO3 只有老 SO 用户才知道这一点,因为如此关注This 链接。仍然几乎所有基本的 C 书籍都以可移植性和向后兼容性为借口遵循 malloc 类型转换.

标签: c variables memory memory-management scope


【解决方案1】:

不,a 具有本地范围(在括号之间声明),因此在右括号处它将被清除。

如果您希望它在整个程序中持续存在,请将其声明为 static 或将其放在任何大括号之外,最好在使用它之前。

这具有让编译器为您初始化它的额外好处。

您可以尝试以下方法:

#include <stdio.h>
int a;

int main()
{
    static int b;

    int c;

    printf("%d, %d, %d\n", a, b, c); /* a and b should print 0, printing c is undefined behaviour, anything could be there */

    return 0;
}

正如 Bathsheba 所指出的,static 变量在多线程环境中使用时应谨慎使用。

【讨论】:

  • 不错的答案;如果您提到使用静态会破坏多线程,我会 +1。
  • 你不需要多线程。简单的递归就足以破坏它。
【解决方案2】:

当您到达带有 printf 的行之后的 } 时,a 被销毁(从堆栈中弹出),所以不,它不会保留在您的注释行的内存中。

【讨论】:

  • 我确信这在 C 中是特定于实现的——即:尽管您不能再通过名称访问它,但它可能仍会占用堆栈空间。
  • 它很可能在内存中,因为实现只需移动堆栈光标就可以了。您可能会发现在大括号之后实例化另一个 int 会完整地恢复原始值。但是,依靠它是在自找麻烦。可能是UB。
【解决方案3】:

首先:它不是特定于实现的。 C 标准明确规定,离开块会破坏具有自动(本地声明)生命周期的对象:

对于这样一个没有变长数组类型的对象, 它的生命周期从进入它所在的块开始 关联,直到该块的执行以任何方式结束。 [ISO/IEC9899:TC3, 6.2.4, 5]

当然,这很难测试,因为在这种情况下它也失去了作用域。 (相反的方法很容易测试。)但这对于一个正式的原因很重要:如果你有一个指向该对象的指针,它的寿命比对象长,那么程序总是不正确的并且行为是未定义的——甚至是实现让对象活着。 (未定义的行为包括一切正常。)

【讨论】:

  • C 的“生命周期”概念并不像所有这些都那么简单。 “对象的生命周期是程序执行期间保证为其保留存储的部分。” (6.2.4, 1;强调我的)对象生命周期的结束并不意味着空间立即被清理;它只是意味着标准不再保证它存在并且仅适用于该对象。 (无论哪种方式,实现都可能有自己的规则和保证,也可能没有。)
  • 您的报价来自 ISO/IEC9899:TC3?我找不到这个,但是:“一个对象的存储持续时间决定了它的生命周期。有三个存储持续时间:静态、自动和分配。分配的存储在 7.20.3 中描述。”在 6.2.4, 1. 但这没关系:您所指的是一个实现,它持有一个对象不再符合标准。这对编译器开发者很重要。对于应用程序开发人员,生命周期在块离开时结束。甚至一个实现持有一个对象的时间也更长,因为 应用程序员 已经死了。 …
  • … 每个依赖(使用)更长范围的 C 程序都是不正确的 C 程序,即使实现承诺将对象保存更长时间,甚至此实现也符合标准。范围未标记为实现定义。
  • 我的报价是直接从您链接的同一个 PDF 复制/粘贴的。你怎么没看到它对我来说是个谜,因为它实际上是 6.2.4,1 之后的下一句(你刚刚粘贴)。关键是,标准不保证内存会立即被回收。在那之后,它不承诺任何事情。如果编译器做出其他保证,则依赖它们的代码是正确的(如果不可移植)。但是关心堆栈指针特定移动的代码已经严重依赖于 IB;抽象机的定义没有指定堆栈。
  • 你说,你引用“(6.2.4, 1;强调我的)”,你的引用来自6.2.4,2。大概是这个原因,我没看到。我看了6.2.4,1。(有人告诉我这样做。)我没有说,该标准保证立即释放内存。这个简单的与应用程序开发人员无关。不,该程序不符合要求,因为它依赖于某些未标记为实现定义的东西。短语“不保证”用于告诉实现程序员,他可以决定何时释放。
猜你喜欢
  • 2012-02-24
  • 1970-01-01
  • 2020-03-18
  • 2014-09-20
  • 1970-01-01
  • 2021-11-14
  • 2011-12-23
  • 1970-01-01
  • 2010-10-07
相关资源
最近更新 更多