【问题标题】:Will a value live perpetually when there's no reference to it?当没有参考价值时,它会永远存在吗?
【发布时间】:2019-03-23 08:02:17
【问题描述】:

假设以下最小代码:

#include <stdio.h>
char character = 'c';
int main (void)
{
    char character = 'b';
    printf("The current value of head is %c", character);
}

我在main 中覆盖了character
c怎么了?会自动销毁还是永远活在记忆中?

这条评论让我印象深刻:“C 中的变量只不过是命名的内存块”。

【问题讨论】:

  • 这与您的问题没有直接关系,但我认为有一点值得指出。除了清理调用帧,C 不会为你做任何内存管理。即使你覆盖了一个全局变量,它之前的值也不会“自动销毁”(作为一个没有引用的对象),而是在原地被覆盖,因为 C 中的变量只不过是命名的内存块。
  • 我太傻了,这就是我愿意问的问题,如果声明为全局,它将被覆盖。 @EliKorvigo
  • 澄清一下,你知道写char character = 'b';(阴影)和character = 'b';(重新分配)之间的区别吗?
  • 好点,我看了评论后很小心,重新分配是在原地覆盖它@Boann,我想我明白了,你明确指出概念重新分配和阴影的区别
  • C 价值观没有生命。

标签: c


【解决方案1】:

shadowing”全局变量charactermain 函数隐藏了变量,但它仍然是程序的一部分。

如果character 变量被声明为static,那么编译器可能会警告character 变量永远不会被使用并且character 将被优化掉。

但是,character 变量没有声明为static;编译器将假定character 变量可能被外部访问,并将character 变量保留在内存中。

编辑

正如@Deduplicator 所指出的,如果允许,链接器优化和设置可以从最终的可执行文件中省略该变量。然而,这是一个不会“自动”发生的极端情况。

【讨论】:

  • 整个程序优化可能允许省略全局。
  • @Deduplicator - 是的。我更新了答案以反映您的评论。然而,这与所问的“自动”行为相去甚远。链接器假定动态扩展可能使用这些变量。例如,变量version 可能永远不会被程序访问,但会被其扩展使用。
【解决方案2】:

它将继续存在(直到程序终止,就像任何静态存储变量一样)并且您仍然可以访问它:

#include <stdio.h>
char character = 'c';
int main (void)
{
    char character = 'b';
    printf("The current value of head is '%c'\n", character);
    {
        extern char character;
        //in this scope, overrides the local `character` with 
        //the global (extern?) one
        printf("The current value of head is '%c'\n", character);
    }
    printf("The current value of head is '%c'\n", character);
}
/*prints:
The current value of head is 'b'
The current value of head is 'c'
The current value of head is 'b'
*/

本地 extern 声明对于 static 全局变量不能可靠/可移植地工作,尽管您仍然可以通过指针或通过单独的函数来访问它们。


( 为什么static char character='c'; int main(){ char character='b'; { extern char character; } } 不可靠而全局为static

6.2.2p4 似乎也想让它适用于静态,但措辞模棱两可(先前的声明没有链接,而另一个声明有静态/外部链接,那么现在呢?)。

6.2.2p4:

对于使用存储类说明符 extern 声明的标识符 该标识符的先前声明可见的范围,31) 如果先前的声明指定了内部或外部链接,则 在后面的声明中标识符的链接与 在先前声明中指定的链接。如果没有事先声明 可见,或者如果先前的声明没有指定链接,则 标识符有外部链接。

我的 clang 6.0.0 使用 static char character='b'; 接受它,但我的 gcc 7.3.0 不是。

感谢Eric Postpischil 指出这也可以与static 一起使用的模棱两可的可能性。 )

【讨论】:

  • @EricPostpischil 感谢您的评论。我不知道 6.2.2 4。它的意图似乎是它也应该适用于静力学,尽管它的措辞本可以更清楚(明确)。 (无论如何,我已经删除了“不适用于静态”段落。)
  • @EricPostpischil 添加了更多信息。我的 clang 也接受它的静态,但我的 gcc 拒绝它并出现错误。
  • @prl:哦,我忘记了 1989 年的版本。我们确定这不仅仅是前互联网时代的神话吗?
  • 根据this question,这个答案的早期草稿是正确的:人们不能期望重新获得对使用static 声明的标识符的访问权限。尝试这样做具有未定义的行为(请参阅问题和答案),因此 Clang 的行为不违反 C 标准,但不能被严格符合的程序依赖,而 GCC 的行为也不是违规行为,可能是首选。
【解决方案3】:
#include <stdio.h>
char character = 'c';
int main (void)
{
    char character = 'b';
    printf("The current value of head is %c\n", character);
    printc();
}

void printc()
{
    printf("%c", character);
}

这一切都清楚了。它没有被破坏,只是被遮蔽了。

输出: head的当前值为b
c

【讨论】:

    【解决方案4】:

    main 中声明character 之后,该函数中对character 的任何引用都指的是那个,而不是全局范围内的那个。我们称之为阴影

    至于对内存的影响,由于语言采用的as-if规则,你不能说:编译器可能会优化到

    #include <stdio.h>
    int main()
    {
         printf("The current value of head is b");
    }
    

    例如。

    【讨论】:

      【解决方案5】:

      虽然全局变量从程序执行的开始到结束都存在,但它们不能自动访问。

      可以从文件中定义或声明全局变量的位置开始访问全局变量,直到文件末尾。

      如果在函数范围内定义了一个同名变量,则全局变量将存在,但不可访问。

      【讨论】:

      • “可访问”不是一个好词。 C 标准在范围(和可见性)和链接方面定义了这里的问题。标准中定义的“访问”是读取或修改对象,这里讨论的对象在理论上是可访问的,因为有一些方法可以在不使用对象标识符的情况下访问对象。 (就此而言,“全局”和“变量”是不精确的。根据标准,标识符具有文件范围,而不是全局。范围适用到用于命名对象标识符,而不是变量。)
      【解决方案6】:

      补充其他答案:

      试试这个,你就会明白:

      #include <stdio.h>
      
      char character = 'c';
      
      void Check()
      {
        printf("Check: c = %c\n", character);
      }
      
      int main(void)
      {
        char character = 'b';
        printf("The current value of head is %c\n", character);
        Check();
      }
      

      【讨论】:

        【解决方案7】:

        通常,全局变量会保留。由于您的局部变量只会隐藏名称,因此不会影响存储。

        但它也可能取决于链接器设置。链接器可以优化未使用的全局变量。

        【讨论】:

          【解决方案8】:

          您有两个名为character 的独立变量:一个在文件范围内设置为“c”,其生命周期是程序的生命周期,另一个在main 中设置为“b”,其生命周期是它的生命周期范围。

          maincharacter 的定义掩盖文件范围内的定义,因此只能访问后者。

          【讨论】:

          • 如果声明为static char character = 'b怎么样
          • @riderdragon 对于main 中的变量,static 修饰符赋予它整个程序的生命周期。
          • @riderdragon,static 声明的行为不同,正如我在回答中提到的那样,但它不会影响生命周期,只是问题“编译器会优化变量吗?”。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-07-18
          • 1970-01-01
          • 1970-01-01
          • 2011-02-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多