天天看點

【C語言進階】——資料的儲存、大小端(一) (超詳細剖析+代碼解析!)一、資料類型詳細介紹(從大方向分為兩種類型)二、資料類型細分類三、整型在記憶體中的存儲四、大小端介紹

@toc

【C語言進階】——資料的儲存、大小端(一) (超詳細剖析+代碼解析!)一、資料類型詳細介紹(從大方向分為兩種類型)二、資料類型細分類三、整型在記憶體中的存儲四、大小端介紹

一、資料類型詳細介紹(從大方向分為兩種類型)

1.内置類型(C語言本身庫有函數)

【C語言進階】——資料的儲存、大小端(一) (超詳細剖析+代碼解析!)一、資料類型詳細介紹(從大方向分為兩種類型)二、資料類型細分類三、整型在記憶體中的存儲四、大小端介紹

2.構造類型(自定義函數)

自定義函數是系統不自帶的,通過自己的編寫後可以使用的函數。一般的程式設計語言、工作表等都可以編寫自定義函數使用。

編寫自定義函數可以簡化主程式,讓程式的檢查調試更友善

3.類型的意義

類型的意義,可以從以下兩個角度考慮:

1.使用這個類型開辟記憶體空間的大小(大小決定了使用範圍)

比如說使用

char類型

建立的變量,開辟的記憶體空間是

1個位元組

,使用

int類型

4個位元組

2.如何看待記憶體空間的視角

比如:

int a = 0;

float b = 0.0;

雖然 a, b都是占用4個位元組的空間,但是我們在看待a的時候,因為其類型是int,是以我們會把a當做整型來看待,在看待b的時候,因為其類型是float,是以我們會把b當做小數(而非整型)來看待。

二、資料類型細分類

1.整形家族

【C語言進階】——資料的儲存、大小端(一) (超詳細剖析+代碼解析!)一、資料類型詳細介紹(從大方向分為兩種類型)二、資料類型細分類三、整型在記憶體中的存儲四、大小端介紹

2.浮點型家族

【C語言進階】——資料的儲存、大小端(一) (超詳細剖析+代碼解析!)一、資料類型詳細介紹(從大方向分為兩種類型)二、資料類型細分類三、整型在記憶體中的存儲四、大小端介紹

3.構造類型

【C語言進階】——資料的儲存、大小端(一) (超詳細剖析+代碼解析!)一、資料類型詳細介紹(從大方向分為兩種類型)二、資料類型細分類三、整型在記憶體中的存儲四、大小端介紹

4.指針類型

【C語言進階】——資料的儲存、大小端(一) (超詳細剖析+代碼解析!)一、資料類型詳細介紹(從大方向分為兩種類型)二、資料類型細分類三、整型在記憶體中的存儲四、大小端介紹

5.空類型

【C語言進階】——資料的儲存、大小端(一) (超詳細剖析+代碼解析!)一、資料類型詳細介紹(從大方向分為兩種類型)二、資料類型細分類三、整型在記憶體中的存儲四、大小端介紹

例:

【C語言進階】——資料的儲存、大小端(一) (超詳細剖析+代碼解析!)一、資料類型詳細介紹(從大方向分為兩種類型)二、資料類型細分類三、整型在記憶體中的存儲四、大小端介紹

三、整型在記憶體中的存儲

之前講過 一個變量的建立是要在記憶體中開辟空間的。空間的大小是根據不同的類型而決定的。

那接下來我們談談

資料在所開辟記憶體中到底是如何存儲的?

1. 如何儲存

看下面這個例子:

#include<stdio.h>
    int main()
{
    int a = 3;
    int b = -1;
    return 0;
}           

為了檢視a, b在記憶體中的存儲形式,我們在編譯器裡面按F10進入調試,變量a,b建立後,打開記憶體螢幕,輸入& a,& b檢視a,b對應的位址及其内容。

& a:

【C語言進階】——資料的儲存、大小端(一) (超詳細剖析+代碼解析!)一、資料類型詳細介紹(從大方向分為兩種類型)二、資料類型細分類三、整型在記憶體中的存儲四、大小端介紹

&b:

【C語言進階】——資料的儲存、大小端(一) (超詳細剖析+代碼解析!)一、資料類型詳細介紹(從大方向分為兩種類型)二、資料類型細分類三、整型在記憶體中的存儲四、大小端介紹

資料在記憶體中存儲時是按二進制的補碼存儲的

展示記憶體的時候,為了友善展示,

顯示的是16進制資料

什麼意思呢? 我們定義一個變量c,以16進制形式對其指派,然後& c,可以看到:

【C語言進階】——資料的儲存、大小端(一) (超詳細剖析+代碼解析!)一、資料類型詳細介紹(從大方向分為兩種類型)二、資料類型細分類三、整型在記憶體中的存儲四、大小端介紹

c輸入的16進制形式是 11223344 ,存儲的時候是 44332211 接下來下面講:

2. 原碼、反碼、補碼

下面先來了解幾個概念︰原碼、反碼、補碼

計算機中的有符号數有三種表示方法,即原碼、反碼和補碼。

三種表示方法均有符号位和數值位兩部分,符号位都是用0表示′正”,用1表示"負”,而數值位三種表示方法各不相同。

原碼:直接将二進制按照正負數的形式翻譯成二進制就可以。

反碼:将原碼的符号位不變,其他位依次按位取反就可以得到了。

補碼:反碼 + 1就得到補碼。

正數

原碼反碼補碼

三碼合一

負數

的原反補

按照上面的規則進行轉換

整數有兩種,有符号數和無符号數

有符号數-- - 符号位 + 數值位

正數 0 + 數值位

負數 1 + 數值位

int b = -1;
//10000000 00000000 00000000 00000001 - 原碼
//11111111 11111111 11111111 11111110 - 反碼
//11111111 11111111 11111111 11111111 - 補碼
//ff ff ff ff - 十六進制顯示形式

int a = 3;
//00000000 00000000 00000000 00000011 - 原碼、反碼、補碼
//0000 0000 0000 0000 0000 0000 0000 0000 0000 0011
//00 00 00 03 - 十六進制顯示形式           

無符号數 unsigned --- 正整數是一樣的!(隻能表示正整數!)<br/>無符号數 --- 原反補按規則計算

【C語言進階】——資料的儲存、大小端(一) (超詳細剖析+代碼解析!)一、資料類型詳細介紹(從大方向分為兩種類型)二、資料類型細分類三、整型在記憶體中的存儲四、大小端介紹
資料存放記憶體中其實存放的是補碼。

3. 為什麼記憶體中要存儲補碼?

我們首先來看一下 1 - 1 這個例子:

①先按照原碼的方式去計算。

【C語言進階】——資料的儲存、大小端(一) (超詳細剖析+代碼解析!)一、資料類型詳細介紹(從大方向分為兩種類型)二、資料類型細分類三、整型在記憶體中的存儲四、大小端介紹

②接下來用補碼來進行計算:

【C語言進階】——資料的儲存、大小端(一) (超詳細剖析+代碼解析!)一、資料類型詳細介紹(從大方向分為兩種類型)二、資料類型細分類三、整型在記憶體中的存儲四、大小端介紹

在計算機系統中,數值一律用補碼來表示和存儲

。原因在于,使用補碼,可以将符号位和數值域統一處理; 同時,加法和減法也可以統一處理(CPU隻有加法器)此外,補碼與原碼互相轉換,其運算過程是相同的,不需要額外的硬體電路。

怎麼了解補碼與原碼互相轉換,其運算過程是相同的?(以下運算,符号位均不變)

原碼-&gt;取反 + 1-&gt;補碼

補碼-&gt;取反 + 1-&gt;原碼

當然補碼到原碼也可以是:補碼 -&gt; - 1 取反-&gt;原碼

例如 - 1:

11111111 11111111 11111111 11111111 - 補碼

補碼->取反 + 1->原碼

10000000 00000000 00000000 00000000 - 取反

10000000 00000000 00000000 00000001 - +1

補碼 -> - 1 取反->原碼

11111111 11111111 11111111 11111110 - -1

10000000 00000000 00000000 00000001 - 取反

最終得到的結果均是:10000000 00000000 00000000 00000001

四、大小端介紹

1.什麼大端小端

大端(存儲)模式,是指資料的低位儲存在記憶體的高位址中,而資料的高位,儲存在記憶體的低位址中。

小端(存儲)模式,是指資料的低位儲存在記憶體的低位址中,而資料的高位,,儲存在記憶體的高位址中。

#include <stdio.h>
#include <windows.h>
int main()
{
    unsigned int a = -10;
    printf("%d\n", a);//%d有符号數列印
    printf("%u\n", a);//%u無符号數列印
    system("pause");
    return 0;
}           
【C語言進階】——資料的儲存、大小端(一) (超詳細剖析+代碼解析!)一、資料類型詳細介紹(從大方向分為兩種類型)二、資料類型細分類三、整型在記憶體中的存儲四、大小端介紹

對上述代碼能運作的解釋

存:
1000 0000 0000 0000 0000 0000 0000 1010  ->原碼
1111 1111 1111 1111 1111 1111 1111 0101  ->反碼
1111 1111 1111 1111 1111 1111 1111 0110  ->補碼
//因為是int類型,是以在記憶體存儲32位
即 0xfffffff6           

那麼如何存呢?

【C語言進階】——資料的儲存、大小端(一) (超詳細剖析+代碼解析!)一、資料類型詳細介紹(從大方向分為兩種類型)二、資料類型細分類三、整型在記憶體中的存儲四、大小端介紹

可以看出是小端存儲。

解析:

【C語言進階】——資料的儲存、大小端(一) (超詳細剖析+代碼解析!)一、資料類型詳細介紹(從大方向分為兩種類型)二、資料類型細分類三、整型在記憶體中的存儲四、大小端介紹

無符号數 unsigned --- 正整數是一樣的!(隻能表示正整數!)

無符号數 --- 原反補按規則計算

資料存取過程圖解:

【C語言進階】——資料的儲存、大小端(一) (超詳細剖析+代碼解析!)一、資料類型詳細介紹(從大方向分為兩種類型)二、資料類型細分類三、整型在記憶體中的存儲四、大小端介紹

2.為什麼有大端和小端

為什麼會有大小端模式之分呢 ?

這是因為在計算機系統中,我們是以位元組為機關的,每個位址單元都對應着一個位元組,一個位元組為8bit。

但是在C語言中除了8bit的char之外,還有16bit的short型,32bit的long型(要看具體的編譯器)。

另外,對于位數大于8位的處理器,例如16位或者32位的處理器,由于寄存器寬度大于一個位元組,那麼必然存在着一個如果将多個位元組安排的問題。

是以就導緻了大端存儲模式和小端存儲模式。

例如一個16bit的short型x,在記憶體中的位址為ox0010),x的值為0×1122,那麼0x11為高位元組,0x22為低位元組。對于大端模式,就将0x11放在低位址中,即0x0010中,0x22放在高位址中,即0x0011中。小端模式,剛好相反

我們常用的x86結構是小端模式,而KEIL c51則為大端模式。很多的ARM,DSP都為小端模式。有些ARM處理器還可以由硬體來選擇是大端模式還是小端模式。

筆試題:用小程式判斷目前機器的位元組序(大小端)

百度2015年系統工程師筆試題:

請簡述大端位元組序和小端位元組序的概念,設計一個小程式來判斷目前機器的位元組序

如何判斷大端、小端(位元組序)呢?

思路:

int a = 1;

将a的第一個位元組内容拿出來,判斷其是1還是0,1為小端,0為大端。

char* 儲存一個位元組

#include <stdio.h>
int check_sys()
{
 int i = 1;
 //對指針i解引用,可以找存儲的第一個位元組
 //如果得到01,說明存儲的順序是01 00 00 00,則為小端,
 //如果得到00,說明存儲的順序是00 00 00 01,則為大端,
 return (*(char *)&i);
}
int main()
{
 int ret = check_sys();
 if(ret == 1)//0x00 00 00 01
 {
 printf("小端\n");
 }
 else
 {
 printf("大端\n");
 }
 return 0;
 }           
【C語言進階】——資料的儲存、大小端(一) (超詳細剖析+代碼解析!)一、資料類型詳細介紹(從大方向分為兩種類型)二、資料類型細分類三、整型在記憶體中的存儲四、大小端介紹
int check_sys()
{
    int a = 1;
    char* p = (char*)&a;
    if (*p == 1)
        return 1;//小端
    else
        return 0;//大端
}           
int check_sys()
{
    int a=1;
    char*p=(char*)&a;
    //傳回1,小端
    //傳回0,大端
    return *p;
}           
int check_sys()
{
    int a = 1;
    return  *(char*)&a;
}           

繼續閱讀