2016-07-27 109 views
-2

ISO/IEC 9899(TC2)§6.5 - 2表达告诉我们:为什么printf(“%d%d%d”,++ i,i,i ++)是未定义的行为?

之前和下一序列点的对象应具有其存储的值由表达式的评估修饰的至多一次之间。此外,先验值只能读取以确定要存储的值。

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

但今天我刚发现这一行:

§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 ++i SP i SP i++

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

从SP2什么是前一个和下一个SP之间的范围是:++ii其中++i仍然是该值的唯一修改。

如果我们现在采取SP3一切是怎么回事以前的SP(SP2)和下一个SP(调用结束)之间是:

ii++仍然只是一个单一的i在整个修改前一个和下一个SP之间的范围。

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

+0

如果您认为它适合,可以随意倒计时。但请注意,这不仅仅是另一个配合问题。我遇到了一些似乎很奇怪的事情,我对此做了一些体面的研究,并清楚地说明了我的困惑以及为什么它与此有关的其他问题有所不同。如果你仍然认为我错过了某些东西或者没有做出足够的努力,请让我知道你为什么这么想。 – dhein

回答

1

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

试想一下,如果代码是:

void foo (int i1, int i2, int i3) 
{ 
    printf("%d, %d, %d", i1, i2, i2); 
} 

foo (++i, i, i++); 

这将是很清楚的。包装并没有改变任何东西。

+0

你能否详细说明在这些情况下,相关行为之间的顺序点是甚至相关的?或者我应该问一个单独的问题? – dhein

+0

这应该是显而易见的东西,如'scanf'。可能有一些格式说明符可能会使'printf'变得不同,但我想不出任何。也许别人可以。 –

+2

具体说明格式说明符'%n',它将到目前为止打印的字符数写入给定地址。 –

相关问题