有趣的 i和i

2022-04-12 08:02:30 字數 4539 閱讀 4824

作為乙個天天和**「約會」的人來說i++和++i這玩意再熟悉不過了,因為使用頻率太高了。

雖然如此,但也未必見得我們真的了解她,不妨猜猜下面的輸出結果。

1 #inlcude 2

3int 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...