作為乙個天天和**「約會」的人來說i++和++i這玩意再熟悉不過了,因為使用頻率太高了。
雖然如此,但也未必見得我們真的了解她,不妨猜猜下面的輸出結果。
1 #inlcude 23int main(void)4
最後結果是:
i[1] = 6 i[2] = 2
j[1] = 4 j[2] = 4
想要得出正確答案,僅僅知道前+和後+的區別是不夠的,這裡面有兩個坑。
第乙個是cpu處理前+和後+真正的執行過程。
第二個是printf這個「小妾」暗藏一腿。
先把簡單的第二個坑填了,以一般的思維和習慣會下意識的認為printf先計算前面那個表示式(即**中的i[1] 和 j[1]),然後計算後面那個表示式的值(即 **中的i[2]和j[2]),事實卻正好相反,要先算後面再算前面。
要想填平第乙個大坑,我們需要研究編譯後的彙編**。
1@by tid_think
2 @arm-linux-gcc -s test.c -o test.s3
@tiny4412
4.cpu arm1176jzf-s
5 .eabi_attribute 27, 3
6.fpu vfp
7 .eabi_attribute 20, 1
8 .eabi_attribute 21, 1
9 .eabi_attribute 23, 3
10 .eabi_attribute 24, 1
11 .eabi_attribute 25, 1
12 .eabi_attribute 26, 2
13 .eabi_attribute 30, 6
14 .eabi_attribute 18, 4
15 .file "
test.c"16
.section .rodata
17 .align 2
18 .lc0:
19 .ascii "
i[1] = %d i[2] = %d\012\000
"20 .align 2
21 .lc1:
22 .ascii "
j[1] = %d j[2] = %d\012\000"23
.text
24 .align 2
25.global main
26.type main, %function
27main:
28 @ args = 0, pretend = 0, frame = 8
29 @ frame_needed = 1, uses_anonymous_args = 0
3031
@by tid_think
32@關鍵**
33stmfd sp!, @將fp,lr兩個暫存器的值壓棧
34add fp, sp, #4 @fp = sp + 4
35sub sp, sp, #8 @sp = sp + 8
36mov r3, #0 @r3 = 0
37str r3, [fp, #-8] @將r3的值(0)寫入 fp -8
的地方 int i = 0
38mov r3, #0 @r3 = 0
39str r3, [fp, #-12] @將r3的值(0)寫入 fp -12
的地方 int j = 0
40ldr r1, .l2 @將.l2的位址載入到r1
41 ldr r3, [fp, #-8] @將fp -8位址上的值(i = 0
) 給r3
42add r3, r3, #1 @r3 = r3 + 1 ===>i = 1
43str r3, [fp, #-8] @將r3的值(1)寫入 fp -8
的地方 i
44 ldr r2, [fp, #-8] @將fp -8位址上的值(i = 1
) 給r2
45 ldr r3, [fp, #-8] @將fp -8位址上的值(i = 1
) 給r3
46add r2, r2, r3 @r2 = r2 + r 3 = 2
47 ldr r3, [fp, #-8] @將fp -8位址上的值(i = 1
) 給r3
48add r3, r3, #1 @ r3 = r3 + 1 = 2
49str r3, [fp, #-8] @將r3的值(2)寫入 fp -8
的地方 i
50 ldr r3, [fp, #-8] @將fp -8位址上的值(i = 2
) 給r3
51add r3, r3, #1 @ r3 = r3 + 1 = 3
52str r3, [fp, #-8] @將r3的值(3)寫入 fp -8
的地方 i
53 ldr r0, [fp, #-8] @將fp -8位址上的值(i = 3
) 給r0
54 ldr r3, [fp, #-8] @將fp -8位址上的值(i = 3
) 給r3
55add r3, r0, r3 @ r3 = r0 + r3 = 6
56 ldr r0, [fp, #-8] @將fp -8位址上的值(i = 3
) 給r0
57add r0, r0, #1 @r0 = r0 + 1 = 4
58str r0, [fp, #-8] @將r0的值(4)寫入 fp -8
的地方59
movr0, r1 @r0 = r1 給printf傳引數1
60mov r1, r2 @r1 = r2 = 2
給printf傳引數2
61mov r2, r3 @r2 = r3 = 6
給printf傳引數3
62bl printf @呼叫printf列印
63 ldr r1, .l2+4 @開始計算j了............
64 ldr r2, [fp, #-12
]65 ldr r3, [fp, #-12]66
addr2, r2, r3
67 ldr r3, [fp, #-12]68
add r3, r3, #1
69str r3, [fp, #-12
]70 ldr r3, [fp, #-12]71
add r3, r3, #1
72str r3, [fp, #-12
]73 ldr r3, [fp, #-12]74
add r3, r3, #1
75str r3, [fp, #-12
]76 ldr r3, [fp, #-12]77
add r3, r3, #1
78str r3, [fp, #-12
]79 ldr r0, [fp, #-12
]80 ldr r3, [fp, #-12]81
addr3, r0, r3
82mov
r0, r1
83mov
r1, r2
84mov
r2, r3
85bl printf
86mov r3, #0
87mov
r0, r3
88sub sp, fp, #4
89ldmfd sp!,
90 .l3:
91 .align 2
92 .l2:
93.word .lc0
94.word .lc1
95.size main, .-main
96 .ident "
gcc: (ctng-1.8.1-fa) 4.5.1
"97 .section .note.gnu-stack,"",%progbits
彙編**解析:
首先刨去沒用的資訊,直接從 31行開始看
33~35行都是對棧指標的一些偏移和儲存。
從以上彙編**看可以看出簡單的兩句c編譯成彙編就是一大坨,如果用純彙編寫15行左右應該就能搞定 執行效率幾乎是c的20倍……………………
i 和i 的用法
式1的運算過程 第一步,第乙個 i計算後i 1,i計算的結果為1 第二步,然後就是i 的計算後i的值不變仍為1,i 的計算結果為1 第三步,接著計算前一步驟中i 自增後的值,此時i 2,再就是第二i 的計算,i的值不變仍是2,所以這一步中i 的計算結果為2 第四步,同上一步計算前一步驟中i 自增後的...
i和i 的區別
大家都應該知道i 和 i的區別,前者是先使用i的值,然後再增加1,而後者是先增加1然後再使用i的值。但是i 和 i那個更好呢?我們實現角度來看 前者是將i值加1後賦給i,然後返回i本身 而後者是先用個臨時變數儲存i值,然後將i值加1賦給i,然後返回臨時變數的值。內建資料型別他們的效率差不多,看他們的...
i 和 i 的輸出
include include include int main int argc,const char argv 輸出結果為 3 3 3 1 0 0 在vs中 printf輸出時,從輸出表示式右到左計算,然後從右到左入棧,再出棧 vs中的彙編下的 5 int main int argc,const...