访问静态超出范围的未定义行为吗?

Posted

技术标签:

【中文标题】访问静态超出范围的未定义行为吗?【英文标题】:Is accessing a static out of scope undefined behavior? 【发布时间】:2016-10-14 06:02:26 【问题描述】:

在与我的一位同事交谈时,他们说:

foo() 
    int *p;
    
        int x = 5;
        p = &x;
    
    int y = *p;

创建未定义的行为,因为生命周期规则和范围规则确实如此 不指定。

但是:

foo() 
    int *p;
    
        static int x = 5;
        p = &x;
    
    int y = *p;

不是未定义的!您最终会遇到“间接范围界定”问题。

术语的使用听起来不正确。 我知道静态与范围无关。 第二种情况是否已经定义了行为?

【问题讨论】:

评论不用于扩展讨论;这个对话是moved to chat。 【参考方案1】:

是的,第二种情况具有明确定义的行为。 static 变量基本上是一个全局变量,其名称的范围仅限于声明它的范围。它在第一次进入范围时被初始化,然后在程序的整个生命周期中都存在。

所以当我们到达时

int y = *p;

p 指向一个您无法再访问(无法返回该代码)但仍具有有效生命周期的变量。

引用标准[basic.stc.static]

所有没有动态存储时长、没有线程存储时长、非本地变量都有静态存储时长。 这些实体的存储将持续到程序的持续时间

强调我的

第一种情况是未定义的,因为本地范围 x 的生命周期在 处结束,并且在其生命周期结束后尝试引用它是未定义的行为。

【讨论】:

第二种情况是*p = 42;未定义吗? @sunqingyao:没关系,为什么不呢? C 不要求存储位置具有名称。否则,malloc 将毫无用处。【参考方案2】:

引用自 here

静态存储类指示编译器在程序的生命周期内保持局部变量的存在,而不是在每次进入和离开范围时都创建和销毁它。因此,将局部变量设为静态允许它们在函数调用之间保持其值。

所以是的,在第二种情况下,x 在程序的整个生命周期内都存在。

因此定义了行为。

【讨论】:

你在引用什么? 静态存储和staticstorage-class specifier是有区别的。 @Olaf 能否提供一些关于静态存储和存储类说明符之间差异的链接,以便我更好地理解它? 标准对此很清楚。这不是我的答案。在 C++ 中可能会有所不同;我评论的印象是这个问题是关于 C 的——你仍然应该验证自己,我对 C++ 标准不太熟悉。如果手头有权威资源,请不要引用二级/三级资源。 我觉得,这是用比权威资源更简单的语言解释的。无论如何,我会在以后的帖子中关注它。

以上是关于访问静态超出范围的未定义行为吗?的主要内容,如果未能解决你的问题,请参考以下文章

超出数组最大索引的未定义行为

如何检查 std::vector 超出范围的访问

对于char型的,如果超出范围怎样算?

cppcheck 超出范围

致命错误:TableView 中的数组索引超出范围

UICollectionViewFlowLayout 子类在滚动和重新加载时崩溃访问超出范围的数组