为什么printf(“%d%d%d”,++ i,i,i ++)是未定义的行为?

时间:2016-07-27 11:34:25

标签: c c99 sequence-points

ISO / IEC 9899(TC2)§6.5 - 2表达式告诉我们:

  

在前一个和下一个序列点之间,对象的存储值最多只能通过表达式的计算修改一次。此外,先前的值应该是只读的,以确定要存储的值。

这是我记住的,记住的,并会告诉任何人问我为什么标题中的行会产生意想不到的输出。

但今天我刚刚发现了这一行:

§7.19.6 - 1格式化输入/输出功能:

  

格式化的输入/输出函数的行为应该与每个说明符关联的操作之后有一个序列点。

这让我想到了:

虽然

int i = 0;
printf ("%d, %d", ++i, i++);

应该是未定义的,下一个例子应该是所提到的条款:

int i = 0;
printf ("%d, %d, %d", ++i, i, i++);

但输出是:

2, 2, 0

我从来没有见过更好的例子,表明未定义的行为。

但为什么呢? 如果该条款为真

  

“[...]表现得就像在与每个说明符相关联的操作之后存在一个序列点。”

然后将§6.5 - 2下的规则应用到与说明符关联的每个actiosn上,不允许我们跨越该规则,如下所示:

(SP表示相关序列点)

SP 1 ++i SP 2 i SP 3 i++

从上一个和下一个SP之间给定范围内的SP1,++ii存储值的唯一修改。

从SP2开始,上一个和下一个SP之间的范围是++ii,其中++i仍然是该值的唯一修改。

如果我们现在采用SP3,那么之前的SP(SP2)和下一个SP(调用结束)之间的所有事情都是:

ii++仍然只是对前一个和下一个SP之间整个范围内的i进行了一次修改。

那么我在这里解释序列点的工作方式是错误的吗?

1 个答案:

答案 0 :(得分:2)

问题不在于与说明符相关的操作。问题在于计算./dir1/file1:step_2:
./dir1/file2:step_2:
函数的参数,该函数在第一个说明符执行任何操作之前完成。

想象一下,如果代码是:

printf

这里很清楚。包装器不会改变任何东西。