程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 從一個乘法來分析C語言,乘法分析C語言

從一個乘法來分析C語言,乘法分析C語言

編輯:關於C語言

從一個乘法來分析C語言,乘法分析C語言


  昨天碰到一個很奇怪的問題,首先來看這段代碼:

 1 #include<stdio.h>
 2 int main(int argc,char *argv[])
 3 {
 4     long num1 = 203879;
 5     long long num2 = 203879;
 6 
 7     long long res1 = num1 * num1;
 8     long long res2 = num2 * num2;
 9 
10     printf("res1 = %lld\n",res1);
11     printf("res2 = %lld\n",res2);
12 
13     return 0;
14 }

  程序的運行結果如下:

  

  這裡感覺很奇怪,203879並沒有超過4個字節的范圍,但是它的平方超過了,於是我把它的結果存放在一個8字節數中,為什麼最終結果還是顯示溢出了呢?

  然後我又寫了一段程序,把它的匯編代碼拿出來分析了一下?程序如下:

 1 int main(int argc,char *argv[])
 2 {
 3     long muln = 203879;
 4     long long mulnl = 203879;
 5 
 6     long long num1 = 203879 * 203879;
 7     long long num2 = muln * muln;
 8     long long num3 = mulnl * mulnl;
 9 
10     return 0;
11 }

  這裡我分成三種情況,一種是直接的一個整數當乘數,一個是long型的整數當乘數,還有一個是long long型的整數當作乘數,然後分別計算他們的平方,我用gdb調試的結果如下:

  

  其中前兩種情況都溢出了,只有第三種情況正常。然後我們再來查看一下他們的匯編代碼,這是我用objdump反匯編出來的匯編代碼:

  

 1 int main(int argc,char *argv[])
 2 {
 3  8048394:    55                       push   %ebp
 4  8048395:    89 e5                    mov    %esp,%ebp
 5  8048397:    83 e4 f8                 and    $0xfffffff8,%esp
 6  804839a:    83 ec 30                 sub    $0x30,%esp
 7     long muln = 203879;
 8  804839d:    c7 44 24 0c 67 1c 03     movl   $0x31c67,0xc(%esp)
 9  80483a4:    00 
10     long long mulnl = 203879;
11  80483a5:    c7 44 24 10 67 1c 03     movl   $0x31c67,0x10(%esp)
12  80483ac:    00 
13  80483ad:    c7 44 24 14 00 00 00     movl   $0x0,0x14(%esp)
14  80483b4:    00 
15 
16     long long num1 = 203879 * 203879;
17  80483b5:    c7 44 24 18 71 b1 90     movl   $0xad90b171,0x18(%esp)
18  80483bc:    ad 
19  80483bd:    c7 44 24 1c ff ff ff     movl   $0xffffffff,0x1c(%esp)
20  80483c4:    ff 
21     long long num2 = muln * muln;
22  80483c5:    8b 44 24 0c              mov    0xc(%esp),%eax
23  80483c9:    0f af 44 24 0c           imul   0xc(%esp),%eax
24  80483ce:    89 c2                    mov    %eax,%edx
25  80483d0:    c1 fa 1f                 sar    $0x1f,%edx
26  80483d3:    89 44 24 20              mov    %eax,0x20(%esp)
27  80483d7:    89 54 24 24              mov    %edx,0x24(%esp)
28     long long num3 = mulnl * mulnl;
29  80483db:    8b 44 24 14              mov    0x14(%esp),%eax
30  80483df:    89 c1                    mov    %eax,%ecx
31  80483e1:    0f af 4c 24 10           imul   0x10(%esp),%ecx
32  80483e6:    8b 44 24 14              mov    0x14(%esp),%eax
33  80483ea:    0f af 44 24 10           imul   0x10(%esp),%eax
34  80483ef:    01 c1                    add    %eax,%ecx
35  80483f1:    8b 44 24 10              mov    0x10(%esp),%eax
36  80483f5:    f7 64 24 10              mull   0x10(%esp)
37  80483f9:    01 d1                    add    %edx,%ecx
38  80483fb:    89 ca                    mov    %ecx,%edx
39  80483fd:    89 44 24 28              mov    %eax,0x28(%esp)
40  8048401:    89 54 24 2c              mov    %edx,0x2c(%esp)
41  8048405:    89 44 24 28              mov    %eax,0x28(%esp)
42  8048409:    89 54 24 2c              mov    %edx,0x2c(%esp)
43 
44     return 0;
45  804840d:    b8 00 00 00 00           mov    $0x0,%eax
46 }

  首先來看num1的代碼(16~20行),203879(31C67H)平方為41566646641(9AD90B171H),編譯器直接把這個結果計算了出來,然後取出結果的4個字節,存放到了num1中,然後再用符號位來填充高4字節。

  接下來我們再來看num2的代碼(21~27行),首先它把203879存放到eax裡面,再把相乘的平方結果存放到eax裡面,由於eax是32位,所以存放的時候就捨去了高4位,只存放了低4個字節。接下來做的就是判斷這個數的符號位是什麼,然後再用移位運算得到32個1存放在edx裡面,最後再把這個edx的值存放到num2的高四個字節裡面。

 

  OK,通過上面這段匯編代碼分析,我們再來從C語言的概念上來分析這句代碼:

  long long num2 = muln * muln ;

  首先muln是一個4字節的整數,然後muln * muln得到的結果也是一個四字節的整數(這裡產生了溢出),然後再把這個結果轉換成8字節的整數,存放到num2中。所以我們最終得到的結果也是一個溢出的結果。

 

  分析完了之後,發現我這是捨進求遠啊,現在也不知怎麼了,遇到點啥就喜歡反匯編出來看看。。。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved