【C語言】算術轉換與整形提升

算術轉換與整形提升

  就在前天,我做了一道這樣的題,它使我發現我對數值類型轉換這裏的知識很膚淺。所以我整理了一下這方面的知識。
  下面我做測試的平臺是VS 2013 32位環境(小端字節序)。
  這是原題:  

int main()
{
    char u = 128;
    unsigned char s = 128;
    unsigned short us;
    us = s + u;
    printf("us = 0x%x\n", us);
    us = (char)s + u;
    printf("us = 0x%x\n", us);
    us = (unsigned char)u + s;
    printf("us = 0x%x\n", us);
    return 0;
}

算術轉換

  C語言在處理不同類型數值之間的運算時是有一定的規律的。需要先將兩個操作數轉換爲相同的類型才能進行運算。而類型的轉換的規律如下圖:
  int
  unsigned int
  long int
  unsigned long int
  float
  double
  long double
  這裏寫圖片描述
  這裏的轉換是自動由低向高發生的(當然,強制類型轉換是根據用戶意願進行的),例如:intunsigned int進行運算,編譯器會將低級別的int轉換爲unsigned int再進行計算。而這個轉換編譯器並沒有對它在內存中的值做出改變,而是使用了不同的讀取方式,編譯器將原本的int的符號位也當成數值大小進行讀取。。
  而這裏沒有提到的charunsigned charshortunsigned short類型在運算時都會自動爲‘升級’爲int型再進行運算。也就是我們所說的整形提升
  

整形提升

  相應的,不同的低級別的類型向高級別類型整形提升的過程也是不太一樣的。
    
  這裏的轉換的規律是:
  unsigned char在轉化時,編譯器會將他們當成正數進行轉化,在高位補0,補全後就是它的補碼
  signed char轉化時,編譯器則會根據他們的正負將他們的高位全部補0或補1,補全後就是它的補碼
  我們再返回來看開頭我遇到的那個題:

int main()
{
    char u = 128;
    unsigned char s = 128;
    unsigned short us;
    us = s + u;
    printf("us = 0x%x\n", us);
    return 0;
}

  usigned char型的,在與類型爲unsigned char型的s進行加法運算時需要進行類型提升,提升爲int型,
  因爲在u進行初始化時,將128賦值給了u,而signed char的取值範圍是-128 ~ 127,這裏的127的原碼是0111 1111,加一就是1000 0000,也就是-128,所以其實在u中存放的是-128這個數。-128的補碼也是1000 0000
  那麼在類型提升時,編譯器會將它當作負數進行補全,高位補1,它在內存中即是0xffff80
  而sunsigned char型的,在提升時,編譯器認爲它是正數,所以高位補0,它在內存中爲0x000080

    00000000 00000000 00000000 10000000   //s的補碼  無符號相當於正數,原反補一樣,提升爲整型時,高位補0,
    11111111 11111111 11111111 10000000   //u提升爲整型的補碼 u是signed char
+   -----------------------------------
    10000000 00000000 00000000 00000000

  它倆相加後,結果爲:0x80000000,在賦值unsigned shortus時將結果的低位兩個字節(16位)截斷賦值給us,所以us中保存的是0x0000
  再看下面兩個語句:

int main()
{
    char u = 128;
    unsigned char s = 128;
    unsigned short us;
    us = (char)s + u;
    printf("us = 0x%x\n", us);
    return 0;
}

  這裏將s先強制類型轉換爲signed char型,再進行運算。
  而s一旦轉換爲signed char型,它的最高位就會表示符號位,其表示的值就會變爲-128,在提升爲整型時與u就有了相同的待遇。
  所以這裏us的補碼都爲0xffff80,它倆的相加結果如下:

    11111111 11111111 11111111 10000000   //u提升爲整型的補碼 u是signed char
    11111111 11111111 11111111 10000000   //s被強制類型轉換後,與u有了相同的待遇
+   -----------------------------------
    11111111 11111111 11111111 00000000

  最終編譯器將相加結果截取低位的16位(兩個字節)存放到了unsigned short型的us中。這時us中存放的值是0xff00
  最後我們再看剩下兩條語句:

int main()
{
    char u = 128;
    unsigned char s = 128;
    unsigned short us;
    us = (unsigned char)u + s;
    printf("us = 0x%x\n", us);
    return 0;
}

  先將u強制類型轉換爲unsigned char,此時u的最高位符號位變爲數值大小,u的值變爲128,進行整型提升時,u被編譯器當作正數,高位補0,提升後,u在內存中表示爲0x000080
  同樣的s類型爲unsigned char,整型提升後在內存中表示爲0x000080,兩者相加:

    00000000 00000000 00000000 10000000  //u強制類型轉換爲unsigned char類型後整型提升
    00000000 00000000 00000000 10000000  //s作爲unsigned char類型的整型提升
+   -----------------------------------
    00000000 00000000 00000001 00000000  

  最終編譯器將相加結果截取低位的16位(兩個字節)存放到了unsigned short型的us中。這時us中存放的值是0x0100
  我們通過在vs2013下運行這段代碼查看最終結果如下:
  這裏寫圖片描述



如果我的文章裏的解答有問題,希望小夥伴們積極指出

全文完,感謝瀏覽

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章