use*_*833 6 c operator-precedence undefined-behavior sequence-points language-lawyer
考虑以下C程序:
int i = 0;
int post_increment_i() { return i++; }
int main() {
i = post_increment_i();
return i;
}
Run Code Online (Sandbox Code Playgroud)
关于2011版C标准(称为C11),以下哪种替代方案是正确的:
C11标准的相关摘要:
5.1.2.3程序执行
访问易失性对象,修改对象,修改文件或调用执行任何这些操作的函数都是副作用,这些都是执行环境状态的变化.表达式的评估通常包括值计算和副作用的开始.左值表达式的值计算包括确定指定对象的身份.
之前排序的是由单个线程执行的评估之间的不对称,传递,成对关系,其在这些评估中引起部分顺序.给定任何两个评估A和B,如果A在B之前被排序,那么A的执行应该在B的执行之前.(相反,如果A在B之前被排序,则B在A之后被排序.)如果A没有排序在B之前或之后,A和B都没有排序.当A在B之前或之后进行测序时,评估A和B是不确定的,但是未指定哪一个.13表示式A的评价与B之间的序列点的存在意味着,在附件中给出与B.(序列点的摘要相关联的每一个值的计算和副作用与前A相关联的每一个值的计算和副作用进行测序C.)
13)未经测试的评估的执行可以交错.不确定顺序的评估不能交错,但可以按任何顺序执行.
6.5表达式
表达式是操作符和操作数的序列,其指定值的计算,或指定对象或函数,或者生成副作用,或执行其组合.在运算符的结果的值计算之前,对运算符的操作数的值计算进行排序.
如果相对于对同一标量对象的不同副作用或使用相同标量对象的值进行值计算,对标量对象的副作用未被排序,则行为未定义.如果表达式的子表达式有多个允许的排序,则如果在任何排序中发生这种未测序的副作用,则行为是不确定的.
6.5.2.2函数调用
在评估函数指示符和实际参数之后但在实际调用之前有一个序列点.调用函数(包括其他函数调用)中的每个评估(在执行被调用函数的主体之前或之后没有特别排序)对于被调用函数的执行是不确定地排序的.94
94)换句话说,函数执行不会相互"交错".
6.5.2.4后缀增量和减量运算符
postfix ++运算符的结果是操作数的值.作为副作用,操作数对象的值递增(即,将相应类型的值1添加到其中).[...]在更新操作数的存储值的副作用之前,对结果的值计算进行排序.对于不确定顺序的函数调用,后缀++的操作是单个评估.
6.5.16分配
赋值运算符将值存储在左操作数指定的对象中.[...]在左右操作数的值计算之后,对更新左操作数的存储值的副作用进行排序.对操作数的评估是不确定的.
6.8声明和块
完整表达式是不属于另一个表达式或声明符的表达式.以下各项都是完整表达式:[...]表达式语句中的表达式; [...] return语句中的(可选)表达式.在完整表达式的评估和要评估的下一个完整表达式的评估之间存在序列点.
上述三种选择分别对应于以下三种情况:
似乎第一种选择通过以下推理链来保持:
考虑规则调用函数中的每个评估(包括其他函数调用)在执行被调用函数体之前或之后没有特别排序,关于被调用函数的执行是不确定的.在6.5.2.2中.假设A:主要的赋值运算符的副作用是这样的"评估".假设B:短语"被调用函数的执行"包括后缀增量运算符的值计算和后缀增量运算符的副作用.根据这些假设和上述规则,可以得出:I)值计算和后缀增量运算符的副作用都是在赋值运算符在main中的副作用之前排序,或者II)值计算和副作用在主要的赋值运算符的副作用之后,后缀增量运算符的顺序排序.
考虑规则更新左操作数的存储值的副作用在左右操作数的值计算之后排序.该规则排除了上述情况.因此,案例II成立.QED
总的来说,这看起来非常强烈.而且,它对应于人们直觉上认为最可能的替代方案.
然而,它确实依赖于对"评估"和"被调用函数的执行"(假设A和B)这两个术语的特定解释以及一个不完全直接的推理线,所以我想把它放在那里看人们是否有有理由相信这种解释是不正确的.注意,脚注94仅在它也适用于呼叫者不与被叫者交错的意义上同样适用于此解释,这反过来暗示"交错"意味着在"abab"意义上交错,因为显然呼叫者与在较弱的"aba"意义上的被叫者.此外,在编译器内联函数然后执行相同类型的优化以激发表达式i = i++具有未定义行为的原因的情况下,备选方案2和3似乎是合理的.
Oli*_*rth 12
[ 我的回答是基于更简单的C99标准,以及C11极不可能引入突破性变化的事实: ]
此代码的此行为是明确定义的:main返回0.有一个在充分表达后的序列点return声明(见C99,附录C),这样的副作用i++采取转让前效果i的main.