在同一个函数中,UB是否可以通过间接访问 – 一个不在范围内的局部变量?

在第二个闭合支撑之后, b只能通过间接通过a

 int main() { int *a; { int b = 42; a = &b; } printf("%d", *a); // UB? return 0; } 

由于b不再是范围,这是UB吗? 我知道从已经返回的函数中取消引用指向非静态局部变量的指针是UB,但在这种情况下,所有内容都在同一个函数中。

这是C ++中的UB,但我不确定C.

是的,它是未定义的行为来访问任何已达到它寿命结束的变量 范围和存储持续时间在这里略有不同。 范围更“变量标识符何时可见?” 并且存储持续时间是“变量本身何时存在?”。

你可以拥有范围和持久性的东西,例如:

 int main (void) { int spoon = 42; // spoon is both in scope and enduring here return 0; } 

或超出范围但持久:

 int main (void) { int *pSpoon; { static int spoon = 42; pSpoon = &spoon; } // spoon is out of scope but enduring here (use *pSpoon to get to it) return 0; } 

您还可以使变量超出范围而不会持久,例如:

 int main (void) { // spoon is neither in scope nor enduring here ("there is no spoon") return 0; } 

事实上,你唯一不能拥有的是范围变量而不是持久。 标识符与存储绑定,因为允许没有后备存储的变量没有多大意义。

我不是在谈论指针,这是一个额外的间接级别 – 范围内的指针变量总是有指针值本身的存储,即使它指向的东西已经结束,或者还没有开始,它的存储持续时间。

未定义的行为在某些情况下可能起作用的事实决不会使行为被定义,事实上,这是未定义行为最烦人的特征之一,因为它有时起作用。 否则它将更容易检测。

在这种特殊情况下, b变量存储持续时间在内部闭合支撑处结束,因此在该点之后尝试访问它是不明智的。


标准的控制部分是c11 6.2.4 Storage duration of objects (略微解释为删除不必要的位):

对象具有确定其生命周期的存储持续时间。 有四个存储持续时间:静态,线程,自动和已分配。

声明标识符没有链接且没有存储类说明符静态的对象具有自动存储持续时间。

对于这样的对象,它的生命周期从入口延伸到与之关联的块,直到该块的执行以任何方式结束。

b仍然在一个不同的嵌套范围内,在您访问它时已经退出并因此销毁了b 。 所以它是未定义的行为 。 在同一个function中的一切都是无关紧要的。

出于变量生命周期的目的,您可以将“已返回的函数”视为嵌套范围,反之亦然。