我读过这个:
...但我仍然不确定这应该如何表现:
int should_be_zero
= stream.seek(4).read_integer()
- stream.seek(4).read_integer();
Stream::seek()
返回*this
,seek
/ read_integer()
分别在某些fseek
上致电fread
/ FILE*
。
这应该像这样返回0:
stream.seek(4)
stream.read_integer()
(在第4位,返回X
,流位置提升为8)stream.seek(4)
stream.read_integer()
(在第4位,返回Y == X
)X - Y == 0
这对我来说非常适合gcc,MinGW和MinGW-w64。但是当我决定扩展对MSVC的编译器支持时,我发现它不再起作用并返回垃圾值。以下是MSVC上实际发生的事情:
stream.seek(4)
stream.seek(4)
(再次)stream.read_integer()
(在第4位,返回X
,流位置提升为8)stream.read_integer()
(在第8位,返回Y != X
)X - Y != 0
这样的执行顺序是否定义明确?如果没有,我怎样才能保护自己不会在未来像这样在脚下射击?
(用括号包围来电似乎没有做任何事情。)
答案 0 :(得分:2)
未定义表达式中的内部执行顺序。仅定义了运算符优先级的明显行为。
因此,在这种情况下,编译器必须两次调用stream.seek(4)
[除非编译器发现它的结果相同"]和{{1两次。但是这些调用的顺序是不确定的(或者C ++标准中的任何术语) - 换句话说,编译器可以按照自己喜欢的方式对这四个调用进行排序。
如果您执行以下操作,您的代码将更具风险:
stream.read_integer()
因为它没有很好地定义两个读取中的哪一个现在按顺序发生 - 它可以先调用第二个read_integer(在偏移0处)或者在偏移8处的搜索和读取之后调用。没有人知道哪个,以及如果你对代码进行细微的修改,编译器甚至可以重新安排它们(例如,它决定以不同的顺序做事情,因为你添加了另一个使用另一个寄存器的变量 - >重新安排代码以更好地使用寄存器...... )
解决方案是引入中间变量:
int x
= stream.seek(4).read_integer()
- stream.read_integer();
这应该在每一段代码中完成,其中执行顺序对于代码的正确性很重要 - 并且要记住"副作用" (例如读取输入,写入输出,修改状态)肯定取决于执行顺序。
答案 1 :(得分:1)
似乎允许这种行为:
<强> 1.9 / 15 强>
除非另有说明,否则评估各个运营商的操作数 个别表达的子表达式未被排除。 [ 注意:在表达式中,在表达式中多次计算 程序的执行,无序和不确定的顺序 不必一致地执行其子表达式的评估 在不同的评估中。 -end note]的计算值 操作符的操作数在值计算之前被排序 操作员的结果。
[...]
当调用函数时(无论函数是否为内联函数),与任何参数表达式相关联的每个值计算和副作用,或者使用指定被调用函数的后缀表达式,都会在执行每个表达式或语句之前对其进行排序。叫功能。 [注意:与不同参数表达式相关的值计算和副作用未被排序。 -end note]
无序表示&#34;左手侧和右手侧的评估可以交错排列&#34;喜欢&#34;评估左表达的一部分,评估正确的表达,评估左表达的其余部分&#34;