在C中,前后增量的结果是右值,我们不能将其赋给右值,我们需要一个左值(另请参见:了解C和C ++中的左值和右值)。通过转到C11标准草案的6.5.2.4
Postfix增量和减量运算符一节,我们可以看到它(强调我的前进):
后缀++运算符的结果是操作数的值。[...]有关约束,类型和转换以及操作对指针的影响的信息,请参见加法运算符和复合赋值的讨论。[...]
因此,后递增的结果是一个值,它是同义词右值,我们可以通过将部分确认此6.5.16
赋值运算符我们哪个段落上方的点约束和结果的进一步理解,它说:
[...]赋值表达式具有赋值后的左操作数的值,但不是左值。[...]
这进一步证实了后递增的结果不是 左值。
对于预递增,我们可以从前缀递增和递减运算符部分中看到6.5.3.1
:
[...]有关约束,类型,副作用和转换以及操作对指针的影响的信息,请参见加法运算符和复合赋值的讨论。
也指向6.5.16
后递增,因此C中的预递增结果也不是左值。
在C ++中,后递增也是rvalue,更具体地说是prvalue,我们可以通过转到5.2.6
Increment and decrement部分来确认这一点:
[...]结果是一个prvalue。结果的类型是操作数类型的cv不合格版本[...]
关于预增量,C和C ++不同。在C中,结果是一个右值,而在C ++中,结果是一个左值,这说明了为什么++ptr = ptr1;
在C ++中有效,但在C中不起作用。
对于C ++,这在“5.3.2
增量和减量”一节中进行了介绍,该节指出:
[...]结果是更新的操作数;它是一个左值,如果操作数是一个位字段,它是一个位字段。[...]
要了解是否:
++ptr = ptr1;
在C ++中定义是否正确,我们需要两种不同的方法,一种用于C ++ 11之前的版本,另一种用于C ++ 11。
在C ++ 11之前,此表达式调用未定义的行为,因为它在同一序列点内多次修改了对象。我们可以通过转到C ++ 11之前的标准草案草稿“5
表达式”中看到以下内容:
除非另有说明,否则未指定单个运算符的操作数和单个表达式的子表达式的求值顺序以及发生副作用的顺序。57)在上一个和下一个序列点之间,标量对象的存储值应修改最多只能通过对表达式的求值一次。
此外,应仅访问先验值以确定要存储的值。对于完整表达式的子表达式的每个允许排序,都应满足本段的要求;否则,行为是不确定的。[示例:
i = v[i ++]
i = 7 , i++ , i ++
i = ++ i + 1
i = i + 1
—结束示例]
我们先递增ptr
,然后再赋值,这是两个修改,在这种情况下,序列点出现在表达式后的;
。
对于C + 11,我们应该转到缺陷报告637:排序规则和示例不一致,这是导致以下结果的缺陷报告:
i = ++i + 1
在C ++ 11中成为定义良好的行为,而在C ++ 11之前,这是未定义的行为。该报告中的解释是我什至看不到的最好的解释,并且多次阅读是很有启发性的,并帮助我以新的视角理解了许多概念。
导致该表达式成为定义明确的行为的逻辑如下:
分配副作用必须在计算其LHS和RHS的值之后进行排序(5.17 [expr.ass]第1段)。
LHS(i)是一个左值,因此其值计算涉及到计算i的地址。
为了对RHS(++ i +1)进行值计算,必须首先对左值表达式++ i进行值计算,然后对结果进行左值到右值的转换。这保证了增量副作用在加法运算的计算之前被排序,而加法运算又在赋值副作用之前被排序。换句话说,它为该表达式产生了定义明确的顺序和最终值。
逻辑在以下方面有些相似:
++ptr = ptr1;
在分配副作用之前对LHS和RHS的值计算进行排序。
RHS是一个左值,因此其值计算涉及到计算ptr1的地址。
为了对LHS(++ ptr)进行值计算,必须首先对左值表达式++ ptr进行值计算,然后对结果进行左值到右值转换。这保证了在分配副作用之前先对增量副作用进行排序。换句话说,它为该表达式产生了定义明确的顺序和最终值。
注意
OP说:
是的,我知道这很麻烦,您正在处理未分配的内存,但是它可以工作并且可以编译。
指向非数组对象的指针被视为加法运算符的大小为1的数组,我将引用C ++标准草案,但C11几乎具有完全相同的文本。在“5.7
加法运算符”部分:
出于这些运算符的目的,指向非数组对象的指针的行为与指向长度为1的数组的第一个元素的指针相同,该对象的类型为其元素类型。
并进一步告诉我们,只要不取消引用指针,指向数组末尾的指针就有效:
[...]如果指针操作数和结果都指向同一数组对象的元素,或者指向数组对象的最后一个元素,则求值不应产生溢出;否则,行为是不确定的。
所以:
++ptr ;
仍然是有效的指针。
++i
,不会在C中返回l值。无论如何,这是UB,因为您在两个连续的序列点之间两次修改了变量。换句话说,不确定值是先增加还是先分配。