关于C语言的表达式的未定义行为有很多,这里讨论讨论其中之一,请参考如下的代码:
int i = 6;
int k = (++i) + (++i) + (++i);
我相信很多初学者看到这段代码,也可能感到很纠结,这段代码的变量k的值,到底是多少?其实这段代码是无定义行为的代码,他的行为取决于编译器.
这个表达式是有副作用的,因为,在序列点之间,变量的值不能保证行为唯一性,也就是说第一次执行完++i,他在内存中的值可能改变。同一个表达式中,对于变量或者对象的多次使用,不应该改变其值,否则,预期的结果就无法保证。
下面,通过在VC平台下,这段代码的执行的结果是 k = 25,那么,为什么会是这样的结果呢?
我们想知道底层到底做了什么?所以,我们可以通过对应的汇编代码来了解底层到底做了什么?
4: int i = 6;
00401028 mov dword ptr [ebp-4],6
5: int k = (++i) + (++i) + (++i);
0040102F mov eax,dword ptr [ebp-4]
00401032 add eax,1
00401035 mov dword ptr [ebp-4],eax
00401038 mov ecx,dword ptr [ebp-4]
0040103B add ecx,1
0040103E mov dword ptr [ebp-4],ecx
00401041 mov edx,dword ptr [ebp-4]
00401044 add edx,dword ptr [ebp-4] ; 通过上面的汇编代码 edx = i = 8将edx的值与变量i的值相加 edx = 16
00401047 mov eax,dword ptr [ebp-4] ; 再次将i的值赋值给eax
0040104A add eax,1 ; eax自增1 eax = 9
0040104D mov dword ptr [ebp-4],eax ; eax -> i i = 9
00401050 add edx,dword ptr [ebp-4] ; edx = 16 i = 9 所以,edx = 25
00401053 mov dword ptr [ebp-8],edx ; edx -> k 所以,k = 25
第一,首先明白++i 是先加后用,i++先用后加
其实,这个是VC编译器优化的结果,当执行int k = (++i) + (++i) + (++i)表达式的时候,首先,将前面的两个++i优化,将i的值自增2 i = 8 假设 m = (++i) + (++i) ,那么, k = m+(++i) 然后执行后面的++i的时候,i = 9 所以,结果是 k = 16 + 9 = 25.
通过,上面的分析,你应该明白未什么这样的结果?但是,根据ANSI C标准给出的规定,这样的代码却是无定义的行为,即UB(Undefined Behavior)
包含多个不确定的副作用的代码的行为总是被认为未定义。
简单而言, “多个不确定副作用” 是指在同一个表达式中使用导致同一对象修改两次或修改以后,又被引用的自增, 自减和赋值操作符的任何组合 甚至都不要试图探究这些东西在你的编译器中是如何实现的(这与许多C 教科书上的弱智练习正好相反, 正如K&R 明智地指出, “如果你不知道它们在不同的机器上如何实现, 这样的无知可能恰恰会有助于保护你。”)
通过以上的解释,我相信你应该明白其中的道理,关于平时写代码必须符合标准的规范性。不然,将会降低代码的可移植性。这篇文章的目的是为了帮助更多被这样问题困扰的初学者,以上都是我的一些个人见解,希望能对你们有所帮助。