我正在编写一个C编译器(以llvm作为后端)进行练习,并且规则后跟the C11 standard §6.2.4。
在“对象的存储期限”部分中,一种情况使我感到困惑:
¶8具有结构或联合类型的非左值表达式,其中 结构或联合包含数组类型的成员(包括, 递归地,所有包含的结构和联合的成员)指 具有自动存储期限和临时生存期的对象。它的 生命周期从计算表达式及其初始值开始 是表达式的值。评估期结束 包含完整表达式或完整声明符的末尾。任何尝试 修改具有临时生存期的对象导致未定义 行为。
我无法想象这种情况在讨论什么情况,尤其是数组成员part(由于这两个具有临时生存期的非左值,具有数组成员的结构与普通的非左值有什么区别吗?< / strong>)有人可以给我一个代码示例来说明这一点吗?
答案 0 :(得分:5)
其中没有数组的临时值不必引用具有自动(或实际上任何)存储持续时间的对象。数组之所以特别,是因为数组到指针的转换是一个可以对数组执行的唯一有用的操作,它隐式地要求它具有一个地址,因此编译器必须为其分配内存(并隐式地为整个对象分配内存)。包含它)。非数组左值没有地址。
struct a { int x; };
struct b { int y[2]; };
void foo(int*);
struct a one();
struct b two();
foo(&one().x); // not legal
foo(two().y); // legal, y has an address
答案 1 :(得分:1)
struct Foo {
int i[1]; //structure contains a member with array type
};
struct Foo getFoo() {
struct Foo foo;
foo.i[0] = 1;
return foo;
}
void test() {
// getFoo().i life time begin;
int *p = getFoo().i; //A non-lvalue expression with structure type
// getFoo().i is automatic storage duration and temporary lifetime
// getFoo().i life time end;
assert(*p == 1); // Any attempt to modify an object with temporary lifetime results in undefined behavior.
}
答案 2 :(得分:-1)
在SEI CERT C Coding Standard
中讨论了该问题(并带有示例)。确实,这是该语言的一种极端情况。
我不在这里复制代码-引用链接就足够了。
这个想法是,在C99中,当函数返回包含数组的结构的那一刻,在包含返回函数的函数的完整表达式结束之前,不得访问/更改该数组。在C11中,直接执行此操作是有效的。
例如,它在C11中有效,但在C99中无效:
++(st().arr)[0] // try to mutate before the full expression ends.
x=st().arr // access array from a temporary returned structure
// before the sequence point at the end of full expression