深入理解電腦系統-之-數值儲存(四)--整數在記憶體中的儲存方式

來源:互聯網
上載者:User
前景回顧

前面我們瞭解到依據CPU的端模式的架構不同,資料的儲存的位元組序也不同

BE big-endian 大端模式,最直觀的位元組序 地址低位儲存值的高位,地址高位儲存值的低位 ,資料填寫時,不要考慮對應關係,只需要把記憶體位址從左至右按照由低到高的順序寫出,把值按照通常的高位到低位的順序寫出,兩者對照,一個位元組一個位元組的填充進去。

LE little-endian 小端模式,則最符合人的思維的位元組序,地址低位儲存值的低位,地址高位儲存值的高位 ,這點比較符合人的思維的位元組序,是因為從人的第一觀感來說,低位值小,就應該放在記憶體位址小的地方,也即記憶體位址低位,反之,高位值就應該放在記憶體位址大的地方,也即記憶體位址高位
任何資料在記憶體中都是以二進位的形式儲存的。

具體參照深入理解電腦系統-之-數值儲存(一)-CPU大端和小端模式詳解

接著我們討論了如何通過程式列印出變數在記憶體中的儲存形式,具體參照深入理解電腦系統-之-數值儲存(二)–C程式列印變數的每一位元組或者位

然後我們瞭解了原碼,反碼,補碼和移碼的表示形式,具體參照深入理解電腦系統-之-數值儲存(三)– 原碼、反碼、補碼和移碼詳解 整型資料概述 整型數

C/C++語言中表示整數、字元和布爾值的算術類型合稱為整型。

字元類型有兩種:char 和 wchar_t。

char 類型保證了有足夠的空間,能夠儲存機器基底字元集中任何字元相應的數值,因此,char 類型通常是單個機器位元組byte)。

wchar_t 類型用於擴充字元集,比如漢字,這些字元集中的一些字元不能用單個 char 表示。

short、int 和 long 類型都表示整型值,儲存空間的大小不同。一般, short類型為半個機器字長,int 類型為一個機器字長,而long 類型為一個或兩個機器字長(在 32 位元電腦中 int 類型和 long 類型通常字長是相同的)。

bool 類型表示真值 true 和 false。可以將算術類型的任何值賦給 bool對象。0 值算術類型代表 false,任何非 0 的值都代表 true。 帶符號和無符號類型

除 bool 類型外,整型可以是帶符號的(signed)也可以是無符號的
(unsigned)。顧名思義,帶符號類型可以表示正數也可以表示負數(包括 0),
而無符號型只能表示大於或等於 0 的數。

整型 int、short 和 long 都預設為帶符號型。要獲得無符號型則必須指定該類型為 unsigned,比如 unsigned long。unsigned int 類型可以簡寫為unsigned,也就是說,unsigned 後不加其他類型說明符意味著是 unsigned int 。
和其他整型不同,char 有三種不同的類型:plain char 、unsigned char 和signed char。雖然 char 有三種不同的類型,但只有兩種表示方式。可以使用unsigned char 或 signed char 表示 char 類型。使用哪種 char 表示方式由編譯器而定。 整數以補碼形式儲存 樣本程式

那現在我們明細了。我們通過下面的程式來查看,整數在記憶體中的表現形式。

#include <stdio.h>#include <stdlib.h>int check_end(){    int   i = 0x12345678;    char *c = (char *)&i;     return (*c == 0x12);}int print_bit(void *addr, int size){    unsigned char *ptr = (unsigned char *)addr;    int print_bytes = 0;    if(ptr == NULL)    {        return -1;     }    for(print_bytes = 0;        print_bytes < size;        print_bytes++, ptr++)    {#ifdef DEBUG        printf("byte %d, data = %02x -=>", print_bytes, *ptr); #endif        for(int print_bits = 7;        print_bits >= 0;        print_bits--)        {            printf("%d", ((*ptr >> print_bits) & 1));        }#ifdef DEBUG        printf("\n");#endif    }    printf("\n");     return print_bytes;}int print_byte(void *addr, int size){    unsigned char *paddr = (unsigned char *)addr;    int print_bytes = 0;    if(paddr == NULL)    {        return -1;     }    while(print_bytes < size)    {        printf("%02x", *paddr);         paddr++;         print_bytes++;     }    printf("\n");     return print_bytes; }int main(void){    if(check_end() == 1)    {        printf("大端模式\n");    }    else    {        printf("小端模式\n");    }    int a = 1;    print_bit((void *)&a, sizeof(a));    int b = -1;    print_bit((void *)&b, sizeof(b));/*X   = -00101011 = 0x0000002B [X]原= 10000000 00000000 00000000 00101011[X]反= 11111111 11111111 11111111 11010100[X]補= 11111111 11111111 11111111 11010101[X]移=01010101*/    int x = 0x2B;    print_bit((void *)&x, sizeof(x));    int y = -0x2B;    print_bit((void *)&y, sizeof(y));    return EXIT_SUCCESS;}
程式分析


不管是原碼,反碼還是,補碼,正數的表示方法是一致的。
但是負數來說,是有區別的。
X = -0X2B = -00101011 = 0x0000002B
[X]原 = 10000000 00000000 00000000 00101011 = 0x8000002B
[X]反 = 11111111 11111111 11111111 11010100 = 0xFFFFFFD4
[X]補 = 11111111 11111111 11111111 11010101 = 0xFFFFFFD5
[X]移 =01010101

由於我們的intel的CPU架構採用小端模式,那麼用補碼儲存的時候,0xFFFFFFD5用小端模式儲存下來,低位元組到高位元組的資料排列下來依次是0x D5 FF FF FF,即11010101 11111111 11111111 11111111
可見,整數是以補碼的形式在記憶體中儲存的 溢出 整型值的表示

無符號型中,所有的位都表示數值。如果在某種機器中,定義一種類型使用8 位表示,那麼這種類型的 unsigned 型可以取值 0 到 255。

C++ 標準並未定義 signed 類型如何用位來表示,而是由每個編譯器自由決定如何表示 signed 類型。這些表示方式會影響signed 類型的取值範圍。

8 位signed 類型的取值肯定至少是從 -127 到 127,但也有許多實現允許取值從-128 到 127。

表示 signed 整數型別最常見的策略是用其中一個位作為符號位。符號位為1,值就為負數;符號位為 0,值就為 0 或正數。一個 signed 整型取值是從 -128到 127。

對於 unsigned 類型來說,編譯器必須調整越界值使其滿足要求。編譯器會將該值對 unsigned 類型的可能取值數目求模,然後取所得值。比如 8 位的unsigned char,其取值範圍從 0 到 255(包括 255)。如果賦給超出這個範圍的值,那麼編譯器將會取該值對 256 求模後的值(其本質就是多出的位被截斷,捨棄掉)。

例如,如果試圖將 336 儲存到 8 位的unsigned char 中,則實際賦值為 80,因為 80 是 336 對 256 求模後的值。
高位元組的進位1被截斷後捨棄掉,這樣就剩下80=336-256

對於 unsigned 類型來說,負數總是超出其取值範圍。unsigned 類型的對象可能永遠不會儲存負數。有些語言中將負數賦給 unsigned 類型是非法的,但在 C/C++ 中這是合法的。

C/C++ 中,把負值賦給 unsigned 對象是完全合法的,其結果是
該負數對該類型的取值個數求模後的值。

所以,如果把 -1 賦給8 位的 unsigned char,那麼結果是 255,因為 255 是 -1 對256 求模後的值。
同樣是截斷,-1用補碼儲存,高位溢出位被截斷,剩下的就是255

當將超過取值範圍的值賦給 signed 類型時,由編譯器決定實際賦的值。在實際操作中,很多的編譯器處理 signed 類型的方式和 unsigned 類型類似。也就是說,賦值時是取該值對該類型取值數目求模後的值。然而我們不能保證編譯器都會這樣處理 signed 類型。

#include <stdio.h>#include <stdlib.h>int check_end(){    int   i = 0x12345678;    char *c = (char *)&i;    return (*c == 0x12);}int print_bit(void *addr, int size){    unsigned char *ptr = (unsigned char *)addr;    int print_bytes = 0;    if(ptr == NULL)    {        return -1;    }    for(print_bytes = 0;        print_bytes < size;        print_bytes++, ptr++)    {#ifdef DEBUG        printf("byte %d, data = %02x -=>", print_bytes, *ptr);#endif        for(int print_bits = 7;        print_bits >= 0;        print_bits--)        {            printf("%d", ((*ptr >> print_bits) & 1));        }#ifdef DEBUG        printf("\n");#endif    }    printf("\n");    return print_bytes;}int print_byte(void *addr, int size){    unsigned char *paddr = (unsigned char *)addr;    int print_bytes = 0;    if(paddr == NULL)    {        return -1;    }    while(print_bytes < size)    {        printf("%02x", *paddr);        paddr++;        print_bytes++;    }    printf("\n");    return print_bytes;}int main(void){    printf("%d\n", sizeof(long));    unsigned char a = 336;    print_bit((void *)&a, sizeof(char));    print_bit((void *)&a, sizeof(short));    printf("%d\n", a);    int *p = &a;    print_bit((void *)p, sizeof(int));    printf("%d\n", *p);    unsigned char b = -1;    print_bit((void *)&b, sizeof(b));    printf("%d\n", b);    union A    {        short ia;        unsigned char ca[2];    }aa;    aa.ia = 336;    printf("%d %d\n", aa.ca[0], aa.ca[1]);    aa.ca[0] = 336;    printf("%d %d\n", aa.ca[0], aa.ca[1]);    aa.ca[1] = 336;    printf("%d %d\n", aa.ca[0], aa.ca[1]);    return EXIT_SUCCESS;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.