C語言筆記之資料類型(二)

來源:互聯網
上載者:User

標籤:

接下來是不同類型之間的強制轉換。當把一個高容量的類型強制轉換為低容量的類型時,會發生截斷:丟棄二進位的高位,只保留低位(二進位的左邊為高位,右邊為低位);而把低容量類型強制轉換成高容量類型時,會發生擴充:在二進位的高位左邊繼續填充數字。擴充分為兩類:零擴充和符號擴充。下面看程式碼範例。

1、截斷

#include <stdio.h>int main(void){    short a = 257;    char b = (char)a;    printf("a = %u, b = %d\n", a, b);     printf("a = %#x, b = %#x\n", a, b);     return 0;}
結果:

a = 257, b = 1a = 0x101, b = 0x1
0x0101被分成兩部分,高位的01和低位的01,char類型只能容納一個位元組,於是取低位的一個位元組後,結果是0x01。
再看一個:

#include <stdio.h>int main(void){    short a = -24368;    char b = (char)a;    printf("a = %d, b = %d\n", a, b);     printf("a = %#x, b = %#x\n", a, b);     printf("a: %d, b: %d\n", sizeof a, sizeof b);    return 0;}
結果:

a = -24368, b = -48a = 0xffffa0d0, b = 0xffffffd0a: 2, b: 1
雖然截斷後的結果是一致的,但是這裡的printf似乎是按四個位元組來列印負數的十六進位。

2、擴充

#include <stdio.h>int main(void){    unsigned short a = 63222u;    unsigned int b = (unsigned int)a;    printf("a = %d, b = %d\n", a, b);     printf("a = %#x, b = %#x\n", a, b);     printf("a: %d, b: %d\n", sizeof a, sizeof b);    return 0;}
結果:

a = 63222, b = 63222a = 0xf6f6, b = 0xf6f6a: 2, b: 4
顯然,雖然列印出來的a和b的二進位表示相同,但是用sizeof運算子計算長度時,發現b佔用了4個位元組,所以b的實際十六進位為:0x0000f6f6。這表明,無符號數的擴充採用0來填充高位,這就是所謂的零擴充。

另外,我發現printf函數列印十六進位時,自動忽略高位的0。

有符號數呢?

#include <stdio.h>int main(void){    char a = -68;    short b = (short)a;    printf("a = %d, b = %d\n", a, b);     printf("a = %#x, b = %#x\n", a, b);     printf("a: %d, b: %d\n", sizeof a, sizeof b);    return 0;}
結果:

a = -68, b = -68a = 0xffffffbc, b = 0xffffffbca: 1, b: 2
呃,又被嚇到了,我不禁懷疑printf函數列印十六進位時存在bug:sizeof顯示a的確只佔一個位元組,所以十六進位只列印0xbc就夠了,為毛還要加上前面一堆f?同理,b的話,0xffbc就夠了。。
不過至少,我們知道低容量的char向高容量的short擴充時,如果其二進位最高位是1,那麼擴充後的高位用1來填充,這就是所謂的符號擴充。

我再驗證一下有符號的正數:

#include <stdio.h>int main(void){    char a = 68;    int b = (int)a;    printf("a = %d, b = %d\n", a, b);     printf("a = %#x, b = %#x\n", a, b);     printf("a: %d, b: %d\n", sizeof a, sizeof b);    return 0;}
結果:

a = 68, b = 68a = 0x44, b = 0x44a: 1, b: 4
恩,雖然也是用0來填充高位,但此時0應被視為正號,仍是符號擴充。

總結上面printf函數的這個小“bug”讓我不禁這樣猜想:是不是在做類型轉換時,無論是截斷還是擴充,先統一變成四個位元組,若不足四個位元組,則採用相應的擴充。

若列印十進位,則從右至左讀取相應的類型長度,然後停止讀取並將讀取的資料列印成十進位;但是列印十六進位時,在讀取了足夠的類型長度後,若讀到0則停止讀入,若讀到1則繼續讀入,直到讀夠4個位元組。


那麼最後,符號轉換和類型轉換一起上會怎樣?

#include <stdio.h>int main(void){    short a = -1;    int b = (int)(unsigned short)a;    unsigned int c = (unsigned)(int)a;    printf("a = %d, a = %#x\n", a, a);    printf("b = %d, b = %#x\n", b, b);    printf("c = %u, c = %#x\n", c, c);    //printf("a: %d, b: %d\n", sizeof a, sizeof b);    return 0;}
結果:

a = -1, a = 0xffffffffb = 65535, b = 0xffffc = 4294967295, c = 0xffffffff
對於b,是先把a由signed short轉換成unsigned short,再轉換成int;而c的話,先做類型轉換,再由signed轉換成unsigned。我們看到結果是不同的,理由在上面說過了。另外,unsigned等價於unsigned int。


現在我們來研究一下有符號數和無符號數運算的問題。
C語言規定,如果參與運算的兩個數一個是有符號的另一個是無符號的,那麼有符號數會被隱式的強制轉換成無符號數,並假設兩個數都是非負數。

這條規則對於算數運算來說,不會導致什麼區別,也就是沒什麼負面作用。然而對於邏輯運算可能會產生意外。

如:-1 < 0u

表面上看沒什麼錯,但這個運算的結果是0,即false。。因為-1被轉換成無符號數後就是4294967295u,它當然不可能小於0u。。。

在比如:2147483647u > -2147483647 - 1

結果也是錯的,因為-2147483648轉換成無符號數後是2147483648。









C語言筆記之資料類型(二)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.