我正在尝试破译导致C99和C11之间发生变化的a note。 该说明中提出的修改最终以C11的6.2.4:8结束,即:
具有结构或联合类型的非左值表达式,其中 结构或联合包含一个数组类型的成员(包括, 递归地,所有包含的结构和联合的成员) 具有自动存储持续时间和临时生命周期的对象。 它的生命周期从评估表达式及其初始值开始 value是表达式的值。它的生命终结了 对包含完整表达式或完整声明符的评估结束。 任何使用临时生命周期修改对象的尝试都会导致 未定行为。
我理解为什么需要进行更改(可以找到一些讨论here。请注意,讨论可以追溯到C11之前)。然而,我不明白的是克拉克·尼尔森写下他的笔记时所说的一句话:
请注意,此方法另外声明了一个例子 这符合C99的要求,是不符合要求的:
struct X { int a[5]; } f();
int *p = f().a;
printf("%p\n", p);
我理解为什么这个例子在C11下是不符合的。我特别不明白的是它是如何符合C99的。并且,如果它是在C99下定义的,它应该做什么,定义打印悬空指针的值?
答案 0 :(得分:8)
我的理解是,在C99中,对象的最佳生命周期是块。因此,虽然6.5.2.2(以及您提到的注释中提到的其他一些§)明确表示您无法在下一个序列点之后访问返回值,但从技术上讲,它的地址不不确定,直到在你离开封闭区块之后(为什么你应该为一个不可访问的对象保留一些存储空间的原因留给读者练习)。因此,像
struct X { int a[5]; } f();
int *p;
{ p = f().a; }
printf("%p\n", p);
在C99和C11中未定义。在C11中,C99中不存在的“临时生命周期”概念允许在完整表达式结束后立即认为指针变得不确定。