這是因爲堆棧溢出的崩潰,mult
和add
函數遞歸調用。
儘管最好使用調試器,但在每個函數中添加printf
都可以幫助觀察程序流。例如改變mult
到:
signed mult(signed g, signed h)
{
printf(" mult %d %d\n", g, h);
if(h == 0 || g == 0) return 0;
return add(g,mult(g,pre(h)));
}
並且類似地,其它功能...的輸出是:
mult -2 2
pre 2
mult -2 1
pre 1
mult -2 0
add -2 0
add -2 -2
pre -2
add -2 -3
pre -3
add -2 -4
pre -4
add -2 -5
pre -5
add -2 -6
pre -6
add -2 -7
pre -7
add -2 -8
pre -8
add -2 -9
pre -9
add -2 -10
...
並繼續調用add
與遞減,直到它崩潰第二個參數。僅當該參數溢出時(在sizeof signed
爲4的情況下,即32比特的情況下超過40億次迭代後發生),條件if(d == 0)
將從add
變爲true
。
當它工作時,我能想到的唯一的事情就是編譯器正在進行優化,可能會刪除函數調用。 試圖在我的Windows的x64機器上原來的程序,從MinGW的有gcc
建:當內置
在有-O3
內置的可執行文件,我跑objdump -S a.exe > a.lst
,這是mult
功能分解:
0000000000401550 <mult>:
401550: 53 push %rbx
401551: 48 83 ec 20 sub $0x20,%rsp
401555: 31 c0 xor %eax,%eax
401557: 85 d2 test %edx,%edx
401559: 89 cb mov %ecx,%ebx
40155b: 75 06 jne 401563 <mult+0x13>
40155d: 48 83 c4 20 add $0x20,%rsp
401561: 5b pop %rbx
401562: c3 retq
401563: 85 c9 test %ecx,%ecx
401565: 74 f6 je 40155d <mult+0xd>
401567: 83 fa 01 cmp $0x1,%edx
40156a: 75 08 jne 401574 <mult+0x24>
40156c: 01 d8 add %ebx,%eax
40156e: 48 83 c4 20 add $0x20,%rsp
401572: 5b pop %rbx
401573: c3 retq
401574: 83 fa 02 cmp $0x2,%edx
401577: 89 c8 mov %ecx,%eax
401579: 74 f1 je 40156c <mult+0x1c>
40157b: 83 ea 03 sub $0x3,%edx
40157e: e8 cd ff ff ff callq 401550 <mult>
401583: 85 c0 test %eax,%eax
401585: 74 0b je 401592 <mult+0x42>
401587: 01 d8 add %ebx,%eax
401589: 74 0d je 401598 <mult+0x48>
40158b: 01 d8 add %ebx,%eax
40158d: 01 d8 add %ebx,%eax
40158f: 90 nop
401590: eb dc jmp 40156e <mult+0x1e>
401592: 89 d8 mov %ebx,%eax
401594: 01 d8 add %ebx,%eax
401596: eb f5 jmp 40158d <mult+0x3d>
401598: 89 d8 mov %ebx,%eax
40159a: 01 d8 add %ebx,%eax
40159c: eb d0 jmp 40156e <mult+0x1e>
40159e: 90 nop
40159f: 90 nop
如可以看出,他並沒有叫任何其他功能,只有本身(callq 401550 <mult>
)。所以編譯器優化/內聯所有其他調用。並通過添加printf
(但僅在此功能,不會打破優化),輸出爲:
mult -2 2
mult -2 1
mult -2 0
mult -2,2: -4
您是否嘗試過使用調試器? – immibis