C 副作用、序列点和未定义的行为

C 副作用、序列点和未定义的行为,c,C,我在一本书中读到以下声明: n = ((i++) > (j)?(i++):(j)); 这本书声称,假设i>j,n有一个意外的值,i增加了两次。我不明白为什么n在这句话之后有一个期望值。 我读了很多关于未定义行为的例子,下面是我的理论(不是书中的解释,因为没有),告诉我我是否正确: 首先,对(i++)>(j)进行求值,i可以递增,也可以不递增 然而,假定i>n,(i++)应该被评估(j),并应用i++的副作用。如果(i++)>(j)的结果为真,则再次计算(i++),否则再次计算(j) i+

我在一本书中读到以下声明:

n = ((i++) > (j)?(i++):(j));
这本书声称,假设i>j,n有一个意外的值,i增加了两次。
我不明白为什么n在这句话之后有一个期望值。
我读了很多关于未定义行为的例子,下面是我的理论(不是书中的解释,因为没有),告诉我我是否正确:

首先,对(i++)>(j)进行求值,i可以递增,也可以不递增 然而,
假定i>n,(i++)应该被评估<我们不知道 无论我是否已经增加,这就是为什么整个 语句未定义。我们不确定是否会返回i或i+1

现在的问题是假设我的理论是正确的-为什么我们不知道 我是否已被递增?如果这行代码是作为If语句编写的,我很确定我之前必须递增。那么为什么化合物不同呢?


谢谢。

操作符
?:
引入了一个序列点,因此这里没有未定义的行为

评估
(i++)>(j)
,并应用
i++
的副作用。如果
(i++)>(j)
的结果为真,则再次计算
(i++)
,否则再次计算
(j)

i++
求值为增量之前的
i
值。因此,假设
i>j
,然后在计算

n = i++ > j ? i++ : j;
以下应该是正确的:

n = iorig + 1
i = iorig + 2
n=iorig+1
i=iorig+2
编辑

6.5.15条件运算符

4计算第一个操作数在其评估和 第二个或第三个操作数的求值(以求值的为准)。第二个操作数 仅当第一个比较值不等于0时才计算;第三个操作数仅当 第一个值等于0;结果是第二个或第三个操作数的值 (以计算值为准),转换为下述类型。110)
110)条件表达式不会产生左值。
你已经在标题中回答了你的问题。阅读序列点。@WumpusQ.Wumbley:谢谢,简历撤回。#主题外:我想我在查找相关信息时发现了邪恶的来源之一:(免责声明:不要遵循此指南!)哦,我的。。。这个网站应该向联邦调查局报告:)毕竟这是一个有趣的陷阱,因为我会打任何试图将这样的代码投入生产的人;)@JeffY:6.5.15/4:“对第一个操作数求值;在其求值与第二个或第三个操作数求值之间有一个序列点(以求值的为准)。”正确。原文被删除以避免混淆。@JohnBode哇,我想你们都证明了这本书是错的(《C编程,现代方法》第二版,第323页,如果你们好奇的话)。也许第一个操作数之后的这个序列点对C99或其他什么东西来说是新的,本书也介绍了旧的C89。无论如何,非常感谢你@诺姆索洛维奇:不要认为C99是新的;我很确定C89也是如此。所有的书都有错误,即使是好的。从80年代中期起,我就开始参考Harbison&Steele,但即使他们偶尔也会搞砸。我总的来说听说过关于金的好东西,所以我怀疑这本书总体上是一本坏书。@JohnBode它确实是一本好书:)再次感谢你为我澄清这一点,你太棒了:)