c語言中的類型轉換

    首先引出一個問題,這是我在編寫模擬器程序的時候遇到的,我們有如下的類型轉換:

       int16_t     v16s;
       uint16_t   v16u;
       int32_t     v32s;
       uint32_t   v32u;

       v16s = 0xf08b;     v16u = (uint16_t)v16s; //請問此時v16s和v16u在二進制表示形式上有什麼不同嗎? No.1
       v32s = (int32_t)v16s;      v32u = (uint32_t)v16s; //請問此時v32s和v32u在二進制表示形式上相同嗎? No.2
       v16s = 0x0f8b;  v32s=(int32_t)v16s;   v32u=(uint32_t)v16s; //請問此時v32s和v32u的值又是多少? No.3
       v32s = 0xffff0fb8; v16s=(int16_t)v32s; v16u=(uint16_t)v32s;//請問此時v16s和v16u的值是多少? No.4
       v16s = 0xf08b; v16u=0xf08b;  v32s=(int32_t)v16s; v32u=(uint32_t)v16u; //請問此時v32s和v32u的值是多少? No.5

首先告訴大家答案:

  1. No.1:請問此時v16s和v16u在二進制表示形式上有什麼不同嗎?
    二者在二進制表示形式上沒有區別,都是0xf08b,所以如果不進行運算操作,在同樣長度的簡單數據類型之間進行強制類型轉換是不必要的,編譯器會略去你的工作,不信的話,你可以查看生成的彙編代碼,對於No.1問題對轉換語句,根本就不生成代碼!!
  2. No2:請問此時v32s和v32u在二進制表示形式上相同嗎?
    二者在二進制表示形式上是相同的!都是0xfffff08b!這裏可能會犯錯的地方在 v32u=(uint32_t)v16s這個語句上,我就是這麼犯的錯誤。按照我錯誤的理解是:0xf08b → 0x0000f08b!這是不對的!原因後面再告訴你(當然如果你C語言學的夠好,就覺得我再弄小兒科了^_^,照顧一下後進者)。
  3. No.3:請問此時v32s和v32u的值又是多少?
    此時v32s和v32u的值都是 0x00000f8b!
  4. No.4:請問此時v16s和v16u的值是多少?
    此時v16s和v16u的值都是0x0fb8!
  5. No.5:此時v32s的值是0xfffff08b,v32u的值是0x0000f08b。在進行自動類型轉換的時候,如果原來的數是無符號數,那麼在擴展的時候,高位填充的是0;如果是有符號數,那麼高位填充的時符號位!這一點有點類似於“>>”操作符,當無符號數右移的時候,高位填充的是0;有符號數右移的時候,高位填充的是符號位。
    好了,下面我就來告訴你,爲什麼是上面的結果。這就需要我們回頭複習一下C語言的有關類型轉換的操作。C語言的類型轉換,可以分爲兩種:自動類型轉換(隱式類型轉換,有編譯器幫你去完成)和強制類型轉換(你知道自己想要什麼,所以才轉換)。
    對於自動類型轉換,最常見的就是混合運算以及賦值運算,還有一種就是函數值的類型轉換
  1. 賦值運算:自動把“=”右邊的表達式的類型轉換成“=”右邊的變量的類型,例如 int a=4.5; a的值實際是4!
  2. 混合運算:就是一個運算表達式當中包含了多個類型,這時候就需要有類型轉換。當運算符兩邊的操作數類型不同時,其中一個操作數就要經過類型轉換以和另一個操作數的類型相一致,然後才能進行運算。
    變換操作數採取就高不就低的原則,即級別低的操作數先被轉換成和級別高的操作數具有同一類型,然後再進行運算,結果的數據類型和級別高的操作數相同。

           高        double    ←←    float
           ↑          ↑             
           ↑         long     
           ↑          ↑
           ↑        unsigned
           ↑          ↑
           低         int
          ←←    char,short

                 自動轉換順序表

  3. 函數返回值的類型轉換: int f1(){ return 36.8;}
    強制類型轉換運算符
    可以利用強制類型轉換運算符將一個表達式轉換成所需類型:
    例如:
  (double)a       (將a轉換成double類型)
     (int)(x+y)      (將x+y的值轉換成整型)
     (float)(5%3)    (將5%3的值轉換成float型)
     (int)(1.5+2.3) = ? 
      (int)1.5+2.3=?
    注意,表達式應該用括號括起來。如果寫成(int)x+y 則只將x轉換成整型,然後與y相加。

    講到這裏,您或許就明白了,哦,原來我們是使用了強制類型轉換的語法,但是程序實質上卻是自動類型轉換! 所以在執行了語句:v16s = 0xf08b;  v32s=(int32_t)v16s;    v32u=(uint32_t)v16s; 後v32s和v32u的二進制表示形式纔是一樣的!
    對於從高到低的強制轉換,實質上就是一個截斷的操作,只把低端需要的部分保留,其餘的部分直接扔掉了。所以對於語句:
v32s = 0xffff0fb8; v16s=(int16_t)v32s; v16u=(uint16_t)v32s; 執行之後v16s和v16u的二進制表示形式纔是一樣的!
    注:我一直強調的都是它們的二進制表示形式是否相同,而沒有說它們的值是否相同,因爲同樣的二進制表示形式,你把它當作有符號數和無符號數的值在決大部分的情況下都是不同的(除了最高位爲0的相同外,其他都不同)

    混合運算

 混合運算是指在一個表達式中參與運算的對象不是相同的數據類型,例如:
  2*3.1416*r 3.1416*r*r 3.6*a%5/(*b)+'f';
 如果r爲int型變量,a爲float型變量,b爲double型變量,則以上三個表達式中涉及到的數據類型有整型、實型、字符型,這種表達式稱爲混合類型表達式。對混合類型表達式的求解要進行混合運算,此時首要的問題是對參與運算的數據進行類型轉換。

下面給出類型轉換的示例,以加深理解。設有如下變量說明:
  int a, j, y; float b; long d; double c;
  則對賦值語句:
  y=j+'a'+a*b-c/d;
  其運算次序和隱含的類型轉換如下:
  ① 計算a*b,由於變量b爲float型,所以運算時先由系統自動轉換爲double型,變量a爲int型,兩個運算對象要保持類型一致,變量a也要轉換爲double,運算結果爲double型。
  ② 由於c爲double型,將 d 轉換成 double 型,再計算 c/d,結果爲double型。
  ③ 計算j+'a',先將'a'(char型)轉換成整型數再與j相加,結果爲整型。
  ④ 將第1步和第3步的結果相加,先將第3步的結果(int)轉換成double型再進行運算,結果爲double型。
  ⑤ 用第4步的結果減第2步的結果,結果爲double型。
  ⑥ 給y賦值,先將第5步的結果double型轉換爲整型(因爲賦值運算左邊變量y爲整型),即將double型數據的小數部分截掉,壓縮成int型,然後進行賦值。
  以上步驟中的類型轉換都是C語言編譯系統自動完成的。
發佈了35 篇原創文章 · 獲贊 6 · 訪問量 26萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章