不是左值和序列点限制的数组

时间:2014-09-10 07:08:58

标签: c

在ISO C99中,非左值的数组仍然会衰减为指针,并且可能是下标的,尽管它们可能不会在下一个序列点之后被修改或使用。 (source

据我所知,此功能允许在函数返回包含数组的结构的情况下进行数组索引,这在C89中是不允许的(http://yarchive.net/comp/struct_return.html

请您帮助我理解为什么在下一个序列点之后使用/修改它有限制?

1 个答案:

答案 0 :(得分:7)

注意,引用的文本OP来自GCC文档。来自C99的相关文本支持报价:

C99 6.5.2.2/5

  

如果尝试修改函数调用的结果或在下一次调用之后访问它   序列点,行为未定义。

以及前言中的更改列表:

  

将数组转换为指针,不限于左值

我没有要比较的C89文本,但C99对数组到指针转换的描述(6.3.2.1/3)没有提到对数组作为左值的任何限制。另外,关于下标的C99部分(6.5.2.1/2)讨论了表达式为后缀表达式,它也没有提到左值。


考虑以下代码:

struct foo
{
     char buf[20];
};

struct foo foo(char const *p) { struct foo f; strcpy(f.buf, p); return f; }

int main()
{
     char *hello = foo("hello").buf;
     char *bye = foo("bye").buf;

     // other stuff...

     printf("%s\n", hello);
     printf("%s\n", bye);
}

指针hellobye指向哪里?这个子句的目的是为了使这些指针无限期地保持有效,编译器不必将所有返回的对象保留在内存中。

相反,hello仅在本案例中的下一个;(或一般的下一个序列点)之前有效。这使得编译器可以自由地将值作为隐藏指针参数实现返回结构,正如Chris Torek在他的优秀帖子中所描述的那样,可以释放"释放"在当前声明的最后。

NB。 C99的情况并不像Chris的帖子中描述的那么简单,因为以下内容必须有效:

printf("%s %s\n", foo("hello").buf, foo("bye").buf);

我的gcc 4.8安装似乎是正确的 - 适用于-std=c99,而segfaults适用于-std=c89