【问题标题】:What is the linkage of a block scope identifier with static storage duration?块范围标识符与静态存储持续时间的联系是什么?
【发布时间】:2015-01-10 17:57:59
【问题描述】:

我相信答案是没有链接,因为标准只保证具有静态存储持续时间的文件范围标识符具有内部链接。但是,似乎递归调用具有静态存储持续时间的标识符的函数不会为局部变量强加额外的内存。换句话说,在递归过程的任何阶段,标识符总是表示同一个对象,这很奇怪,因为它没有链接。这是为什么呢?

void recursive(void) {
    static int a;
    printf("%d", &a);   // it repeatedly spits out the same address.
    recursive();
}

【问题讨论】:

  • 为什么不吐出同一个地址?声明 a static 的全部意义在于使其在调用中持久化。
  • 而且它没有基本情况。所以在某一时刻它会耗尽所有堆栈空间......
  • 它肯定是与包含函数相同的链接。只有自动变量没有链接。
  • @jamesdlin 我同意这应该是考虑到堆栈的方式。但是,在我看来,它有点像链接,因为每个新的 a 都表示同一个对象(=链接的用途)!
  • 联动与您观察到的行为无关。链接是关于将对象名称解析为对象地址的规则。通常,当涉及多个翻译单元(即多个 obj 文件)、共享库等时,它就会发挥作用。

标签: c


【解决方案1】:

局部静态变量没有链接(或者更准确地说,它们的链接是none)。来自 N1570(C11 草案)6.2.2 标识符的链接(强调我的):

6) 以下标识符没有链接:声明为的标识符 不是对象或函数;声明的标识符 成为函数参数;对象的块范围标识符 声明时没有存储类说明符 extern

但是static 说明符强制要求此类变量具有静态存储持续时间,这是一种不同的东西。您指的是对象的生命周期。此类变量表示对象,它们具有整个程序执行的生命周期,并且在概念上在程序实际启动之前初始化一次。

6.2.4 对象的存储时长

2) 对象的生命周期是程序执行期间的一部分 保证为它保留哪些存储空间。对象存在, 有一个固定地址33)保留其最后存储的值 34) 如果一个对象在其外部被引用 生命周期,行为未定义。指针的值变为 不确定它指向(或刚刚过去)的对象何时到达 生命周期结束。

3) 一个对象,其标识符被声明为没有存储类 说明符 _Thread_local,以及具有外部或内部链接或存储类说明符 static,具有静态存储持续时间。它的 生命周期是程序的整个执行过程及其存储的值 在程序启动之前只初始化一次。

【讨论】:

  • 我已经阅读了您刚才提到的所有内容。我只是困惑。假设每个递归阶段都需要一个额外的内存空间,并且该对象一直存在到程序的末尾。在那种情况下,按照标准是违法的吗?我认为这是合法的,因为标准只保证它的生命周期,而不是对象之间的平等。我的意思是这些标识符怎么会表示同一个对象...?
  • @Il-seob Bae:查看更新的答案,尤其是 6.2.4/2。
  • 6.2.4/6 明确指出,每当递归输入块时,每次都会创建一个新的对象实例。我不明白为什么 6.2.4/2 会取消 6.2.4/6。这大约是 object 的生命周期,并且一个对象可以被实例化多次。我认为它们是两种不同的东西。
  • @Il-seob Bae:子条款 6.2.4/6 指的是具有自动存储持续时间(如果您仔细阅读的话)的对象,它们是独立的。
  • 虽然与问题没有直接关系,自动存储时长的对象的生命周期是多少?似乎该标准不能保证它的生命周期。我们是否应该对它通常由堆栈实现这一事实感到满意?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-01
  • 2016-05-18
  • 2015-04-28
  • 2021-08-20
  • 2010-09-22
  • 1970-01-01
相关资源
最近更新 更多