我一直认为,在读取赋值中的正确表达式后缺少序列点会使如下示例产生未定义的行为:
void f(void)
{
int *p;
/*...*/
p = (int [2]){*p};
/*...*/
}
// p is assigned the address of the first element of an array of two ints, the
// first having the value previously pointed to by p and the second, zero. The
// expressions in this compound literal need not be constant. The unnamed object
// has automatic storage duration.
但是,这是 C11 标准委员会草案中“6.5.2.5 复合文字”下的示例 2,版本标识为 n1570,我理解为最终草案(我无权访问最终版本)。
所以,我的问题是:标准中有什么东西可以给出这种定义和指定的行为吗?
编辑
我想准确地解释一下我所看到的问题,以回应一些已经出现的讨论。
根据 dbush 给出的答案中引用的标准的 6.5p2,我们有两个条件明确声明分配具有未定义的行为:
1) 标量对象的副作用相对于同一标量对象的不同副作用是无序的。
2) 相对于使用相同标量对象的值的值计算,对标量对象的副作用是无序的。
第 1 项的示例是“i = ++i + 1”。在这种情况下,由于 ++i 将值 i+1 写入 i 的副作用相对于将 RHS 分配给 LHS 的副作用是无序的。在每一侧的值计算和将 RHS 分配给 LHS 之间存在一个序列点,如下面 Jens Gustedt 的回答中给出的 6.5.16.1 中所述。但是,由于 ++i 对 i 的修改不受该序列点的约束,否则将定义行为。
在我上面给出的例子中,我们有类似的情况。有一个值计算,它涉及创建一个数组并将该数组转换为指向其第一个元素的指针。将值写入该数组的一部分还有一个副作用, *p 写入第一个元素。
所以,我看不出我们在标准中有什么保证,即在将数组地址写入 p 之前,将对数组中未初始化的第一个元素的修改进行排序。这种修改(将 *p 写入第一个元素)与将 i+1 写入 i 的修改有何不同?
换句话说,假设一个实现将示例中感兴趣的语句视为三个任务:第一,为复合文字对象分配空间;第二:将指向所述空间的指针分配给p;第 3 步:将 *p 写入新分配空间中的第一个元素。RHS 和 LHS 的值计算将在赋值之前进行排序,因为计算 RHS 的值只需要地址。这种假设的实现在哪些方面不符合标准?