为什么在c语言中,i=1;i=(++i)+(++i)+(++i)+(++i);得到
在C语言中,尝试写出i=1;i=(++i)+(++i)+(++i)+(++i);这样的代码,是严格禁止的。这种写法,就如同触碰了不该碰的电门,完全属于自寻死路的行为。这在C标准里被称为"未定义行为",这个术语实则传达了更为恶劣的态度:相关情况早已被充分理解并讨论,最终的决定是"不予理睬,任由后果自负"。未定义行为的执行后果是不可预知的,就像掷硬币的随机结果,与"未定义行为"的定义风马牛不相及。
C/C++是一种工程师为满足实际需求而设计的语言。与严谨学术设计的语言不同,C/C++允许一些变通。例如,i++在某些语言中是不允许的,因为它不符合表达式的定义,但在C/C++中被允许,旨在减少代码量或与汇编指令对应。然而,这种非标准的添加打开了潘多拉的魔盒,因为i++不仅改变了变量值,还引入了副作用,这与普通表达式的执行时机不同,从而深刻改变了程序执行结果。
序列点的概念是C/C++中类似分隔符的角色,用于确保在每个拍子结束时,程序状态一致。显然,如果未定义i++内部的执行细节,可以有无数种可能的结果。但如果限制这些细节,可能在某些机器上执行速度变慢,或导致优化算法失效,增加编译器实现的难度。更重要的是,i++是一个改变变量值的指令,而非纯粹的数学表达式。滥用它作为数学表达式,导致的复合表达式缺乏数学与现实意义,任何尝试为其赋予合理意义的规定,都只是要求记忆毫无意义的规则,这不符合C标准制定者的专业水平。
因此,C/C++委员会的决策是,任何类似写法都不予支持。如果有人写出包含"未定义行为"的代码,那么编译器可以生成任何合法的代码结果。"类似情况"指的是不允许一个变量在序列点之间改变两次值,这是对错误本质的禁令,而非列出各种可能错误的清单。
按照上述规则,i=i++显然不是合法的C代码,因为它本身就改变了一次变量i的值,然后又通过赋值操作再次修改了i。这种非法代码的执行结果无法确定,编译器生成的任何代码都是合法的。在现实中,不同编译器、版本,甚至同一编译器在不同编译参数下,结果可能各不相同。对编写这种代码的人,软件公司的一致态度是解雇。
2014年5月6日补充:
曾经有编译器在遇到"未定义行为"时玩起了彩蛋恶搞。著名的gcc在1.17版本下,对于"未定义行为",会尝试运行一些游戏,如NetHack、Rogue或Emacs的Towers of Hanoi,或者输出一条独特的错误信息。
这是一段有趣的小插曲,展示了编译器面对无法确定结果时的趣味性反应。不知道这样的彩蛋是否会让某些编程界的大师发出惊叹,又或者未来的计算机二级考试会出什么更加离奇的题目。
多重随机标签