C 为什么'x-->;0`不是未定义的行为,而`x=x--`is?

C 为什么'x-->;0`不是未定义的行为,而`x=x--`is?,c,operators,decrement,C,Operators,Decrement,大家都知道,这个循环通过零: while (x-- > 0) { /* also known as x --> 0 */ printf("x = %d\n", x); } 但是x=x--会产生收益 这两个示例都需要一些x--的“返回”值,我想这是不存在的。怎么可能定义了x-->0,但x=x--没有定义?因为在x=x--中,您在没有插入序列点的情况下修改了x的值两次。因此,没有定义操作顺序。在x-->0中,x的值被修改一次,并且它清楚地定义了计算x--的结果将是减量之前x的值。

大家都知道,这个循环通过零:

while (x-- > 0) { /* also known as x --> 0 */
  printf("x = %d\n", x);
}
但是
x=x--
会产生收益



这两个示例都需要一些
x--
的“返回”值,我想这是不存在的。怎么可能定义了
x-->0
,但
x=x--
没有定义?

因为在
x=x--
中,您在没有插入序列点的情况下修改了
x
的值两次。因此,没有定义操作顺序。在
x-->0
中,
x
的值被修改一次,并且它清楚地定义了计算
x--
的结果将是减量之前
x
的值。

我不知道你从哪里得到“需要一些x--”的“返回”值,这是不存在的”。首先,你的意思不太清楚。其次,不管你的意思是什么,这似乎与
x=x--
中未定义行为的来源没有任何关系

x=x--
产生未定义的行为,因为它试图在没有插入序列点的情况下修改
x
两次。这里不涉及任何“返回值”的“需要”

x=x--
的根本问题是,它有两个副作用,在未定义的时刻以未定义的顺序出现。赋值运算符引入了一个副作用。postfix
--
操作符引入了另一个副作用。这两种副作用都试图修改相同的变量
x
,并且通常相互矛盾。这就是为什么这种情况下的行为在法律上被宣布为未定义

例如,如果
x
的原始值为
5
,则表达式要求
x
同时变为
4
(减量的副作用)和
5
(赋值的副作用)。不用说,
x
不可能同时变成
4
5


虽然UB不需要出现这种直接的矛盾(如
4
5
)。每次有两个副作用在没有插入序列点的情况下撞击同一变量时,行为是未定义的,即使这些副作用试图将值放入变量匹配中。

只是为了给其他答案添加一些内容,试着阅读序列点。

为了理解这一点,你需要对序列点有一个基本的了解。请参阅此链接:

对于
=
运算符,没有序列点,因此不能保证
x
的值在再次分配给
x
之前会被修改

当您在while循环
x-->0
中检查条件时,将计算
x--
,并在关系运算符计算中使用该值,因此不存在未定义行为的可能性,因为
x
仅被修改一次。

我建议阅读。如果你把
=
不是a的问题放在一起,并且编译器可以自由地交错操作,只要它们没有被一个序列点从你链接的答案中分离出来,你就会看到,也就是说,以下两个序列是合法的:

load i to reg
increment i
assign reg to i
=> i has previous value of i

load i to reg
assign reg to i
increment i
=> i has value of previous value of i + 1

一般来说:避免在一个表达式中对同一个变量赋值两次(这包括通过pre/post++/--)到同一个变量。

Ah,因此
x--
的计算结果为
x-1
,但是
x=x--
中的顺序没有定义?@Radek S:Huh
x--
根本不返回
x
x--
返回
x
的原始值。首先,原始值是减量之前的值(你“之后”从哪里来?)。其次,它不是
x
。它是
x
的原始值。我希望您理解变量和变量值之间的区别。@Radek S:x=x--中没有定义任何内容。该语言表示
x=x--
未定义。这意味着整个事情都是未定义的,而不仅仅是某些事情的“顺序”。@Shaninja:对于未定义的行为来说,似乎工作正常是合理的结果。它还可以返回42并符合要求。在这样的表达中,没有对“正确”结果的合理期望;这取决于您对评估顺序的期望。@Radek S:然而,这一切背后的基本原理是,副作用发生的时间和顺序没有定义。副作用是这里的关键问题
x=x--
有两个副作用,它们会在任何时刻以任何顺序出现。这就是为什么
x=x--
没有定义。我希望你能理解,除了形式上的原因,写
x=x--根本没有意义。要么写
x--本身或替换
x=x--中的第二个
-
带有
1
…@R。我最好换一种方式问它:“
x-->0
为什么不像
x=x--
?”那样未定义,因为
x
只修改一次。从常识的角度来看,因为这是
--
操作符的全部要点:它修改和左值,并生成旧值。没有可疑之处。例如,
(x=1)+(x=1)
调用未定义的行为。