c語言 數據存儲與原碼 反碼 補碼詳細解析

前言

學習本章你會瞭解:

1.數據類型詳細介紹

2.整形在內存中的存儲:以及瞭解原碼、補碼、反碼

3.大小端字節序的介紹和判斷

4.浮點型在內存中的存儲解析

1.數據的類型介紹

在學習數據儲存之前,讓我們先認識一下數據類型。以下這些數據類型是我們初學c語言時的基礎類型以及大小所占字節數。

比如 所占字節數 類型
char 1 //符數據的類型
shot 2 //短整型
int 4 //整形
long (規定sizeof(long)>=sizeof(int) ) 4 //長整型
long long(部分編譯器不支持) 8 //更長的起整數
float 4 //單精度浮點數
double 8 //雙精度浮點數

還有構造類型:

數組類型

結構體類型struct

枚舉類型enum

聯合類型union

指針類型:

int* pa;

char* pb;

float* pc;

void* pd;

除瞭以上類型,實際上還有佈爾類型:_Bool(專門用來表示真假的類型)

舉個栗子(在c99中可用)

#include<stdio.h>
#include<stdbool>
main()
{
_bool flag=true;
if(flat)
printf("hello world")
return 0;
}              //結果就會打印一個hello world

1.1整形傢族

整形傢族中包括int short long,還有char。

char也是整形傢族中的嗎?

答案是:是的,因為char對應的字符的ascii碼值中,字符對應的就是整形。

在這些整形類型之中,還可以分為無符號整形和有符號整型:

int=signed int

short=signed short

long=signed long

那是否char 等於 signed char呢

結果又跟其他整形傢族中的成員不同,在標準情況下char不是等於sign char~(但是在常規編譯器中是相等的)。

2.整形在數據內存中的存儲

我們知道變量創建就是開辟空間,開辟空間的大小由數據的類型來決定。

那麼數據在所在的空間是怎樣儲存的呢?

在vs2019中輸入:

int    a=20;
int    b=-10;

就代表在內存中開辟四個字節的空間

 其中14 00 00 00 就是a十六進制對應反碼的值

和前面相同,f6 ff ff ff就是b十六進制對應反碼的值

我們都知道計算機都是以二進制來存儲信息,那為什麼在內存圖中看到的是十六進制呢?

這僅僅是便於觀察,當以十六進制儲存時,有沒有感到反碼有點長呢,如果換成二進制就更不宜觀察瞭,故規定以十六進制來保存。

提到這裡,什麼是反碼呢?為什麼又反碼的出現呢?

2.1 原碼 反碼和補碼(三種整型數的表示方法)

原碼:原碼就是數字對應二進制的表示方法,其中最後一位數字是符號位,表示正負的,

而小字節序就是二進制對應的是數。

如a的原碼是:0000 0000 0000 0000 0000 1010 

反碼:反碼的數值就是在原碼的基礎之上進行轉換過來的,當數值為正數時,反碼的數據大小跟原碼相同,當數值是負數是,其反碼的值就是在原碼的基礎上,除瞭符號位,其他位都是按位取反。

補碼:補碼數值為正數時,其值大小就是原碼,為負時,其值的大小就是在反碼的基礎之上,在進行加一。

原碼得到補碼取反加一即可,其實補碼得到原碼也是取反加一(感興趣的可以試試)

舉個栗子:

a的原碼 反碼 補碼

原:0000 0000 0000 0000 0001 0100 

反:0000 0000 0000 0000 0001 0100 

補:0000 0000 0000 0000 0001 0100 

b的原碼 反碼 補碼

原:1000 0000 0000 0000 0000 1010

反:1111 1111   1111  1111  1111  0101

補:1111 1111  1111   1111   1111  0110

那我們系統會出現原碼反碼和補碼三種表示方法呢,一種表示方法不行嗎?

我們能想到的,科學傢也能想到,但一種表示方法有缺陷。

就比如說:當計算1+(-1)的時候(計算機隻能實現加法的運算)

統一用原碼的結果是

0000 0000 0000 0000  0000 0001

1000 0000 0000 0000 0000  0001

結果是1000 0000 0000 0000 0000  0010

用補碼計算的結果是:

0000 0000 0000 0000 0000  0001

0111  1111  1111 1111  1111  1111

結果是1000 0000 0000 0000 0000 0000 也就是0

你是不是瞬間知道為什麼要三種表示方法,為什麼有補碼的存在瞭

有沒有get到科學傢的偉大之處

2.2大小端字節序序的介紹

大小端字節序分別是哪一種?

a在內存中的數值44 33 22 11就是小端字節序

那大端字節序就是11 22 33 44

大小端字節序的定義是什麼?

大端字節序:當一個數的低字節序放在高地址處,或者高字節序的放在低地址處時,就是我們所說的大端字節序。

小端字節序:當一個數的高字節序放在低地址處,或者低字節序的放在高地址處時,就是我們所說的小端字節序。

放在倒著就是小端字節序,記住它即可。

為什麼數據要分大小端字節序呢?

大小端字節序來源於於喬納森·斯威夫特的小說《格列佛遊記》,這是因為在計算機系統中,我們都是以字節為單位的,每個地址單元都對應著一個字節,一個字節為8bit,但是在c語言中除瞭8bit的char之外,還有16bit的short型,32bit的long型(看具體編譯器),另外,對於位數大於8位的處理器,例外16位的或者32位的處理器,由於寄存器寬度大於一個字節,那麼必然存在著一個如何將多個字節序排序的問題。因此就導致瞭大端存儲模式,和小端存儲模式。

 那麼怎麼判斷大小端字節序呢?

下面由一個例題來講解:(這是百度2015年系統工程師的筆試題)

用代碼來判斷系統大小端字節序:

int a;
 
char*pa=(char*)&a;
 
if(*pa==1)
 
printf("小端字節序“);
 
else
 
printf(“大端字節序”);

2.3 練習

題一:

//輸出結果是什麼
#include<stdio.h>
int main()
{
char a=-1;
signed char b=-1;
unsigned char c=-1;
printf("a=%d,b=%d,c=%d",a,b,c);
return 0
}

輸出的結果分別是-1 -1 255

前面兩個很容易理解 signed char與char意思都是有符號的整數,所以打印的結果都是-1.

都是對於無符號來說這時候就要進行整形提升瞭

當char型以整形來打印時過程如下:

原碼:10000001

反碼:11111110

補碼:11111111

unsigned整形提升後:0000 0000 0000 0000 1111 1111

這是的補碼同樣也是: 0000 0000 0000 0000 1111 1111

就是最終c的值。

題二:

​#include<stdio.h>
 
int main()
{
char a=-128;
printf(%u\n",a);  //u就是以無符號的類型打印出來
return 0;
}

-128的原碼: 1000 0000 0000 0000 1000 0000

反碼1111 1111 1111 1111 0111 1111

補碼1111  1111 1111 1111 1000 0000

因為是char型 補碼提取後:10000000

正進行整形提升,因為char是無符號整形,所以提升後:

1111 1111 1111 1111 1000 0000

再以無符號整形形式打印後原反補相同即:1111 1111 1111 1111 1000 0000

再轉化成十進制:4294967169

運行證明以如下

數據的范圍是多少呢?unsigned char與char存放的數據是否相等呢?

事實證明char與unsigned char數據范圍並不一樣

char的整形數據范圍是-128~127,而unsigned char的范圍是0~255;

(short 與unsigned short的整形取值范圍也不一樣

short的整形數據范圍是-32768~32767,而unsigned short能存儲的數據范圍則是0~65535

3.浮點型在內存中的存儲

首先列出一個常見浮點數表示方法:

1E10 可能你並不知道這是什麼意思;

實際上他的意思是1.0*10^10;

3.1 先舉一個例子

#include<stdio.h>
int main()
{
int n=9;
float*pFloat=(float*)&n;
printf("n的值為:%d\n",n);
printf("*pFloat的值為:%f\n",pFloat);
*pFloat=9.0;
printf("num的值為:%d\n",n);
printf("*pFloat的值為:%f\n",*pFloat);
return 0;
}

n的值為:9

*pFloat的值為:0.00

num的值為:1091567616

*pFloat的值為:9.000000

  這個結果是否跟你想的一樣呢?

 其實n的值與最後一個*pFloat的值可能我們很容易知道(也可能是猜的 哈哈)

在求解這道題之前讓我們先瞭解這個題的知識吧~

3.2 浮點數儲存的規則

IEEE(電氣和電子工程協會754標準)標準規定:

任何二進制的浮點數都可以以這種標準表示出來:

基本公式是:(-1)^S*M*2^E;(這裡的E是無符號類型)

其中M是有效數子,E是指數,S用來表示正負;

舉個栗子:

5.5——10進制的表示

轉化為二進制的結果是:101.1;

用公式表示為:(-1)^0 (1.011)*2^2    此時S=0,M=1.011,E=2;

 對於64位浮點數,最高位1位是符號位s,接著是11位是指數E, 剩下的52位是有效數字。

如果E為八位,他的取值范圍0~255,如果E為11為,他的取值范圍0~2047;

有兩個極限 

當E為0時,此時的真實的E為1-127=-126;此時的數值根據公式,也就是無限接近與0;

當E為254時,此時的真實的E為254-127=127;此時的數值根據公式,也就是無窮大。

說到這裡,你可能有一點疑惑,為什麼都要減一個127,這是因為避免出現E為負數的情況(因為這裡的E是無符號整形),在真實的E的基礎上加瞭127,所以為瞭得到求出真實的E,就需要減去一個127.

 現在回到原來的題目之上

0000 0000 0000 0000 0000 0000 0000 1001–九的原碼反碼與補碼。

這裡的0 是 s;00000000為E;0000000000000000001001為m

此時(-1)^0*0.00000001*10*2^(-126)

由於float默認隻打印小數點後六位,所以最終打印0.000000;

九的轉化位二進制:1.001;

1.001*2^3

=0 M=1.001 E=3;

0100 0001 0001 0000 0000 0000 0000 0000

再以整形的形式打印的話,此時的值就是0100 0001 0001 0000 0000 0000 0000 0000就是num的補碼,由於符號位是0,所以最終的原碼等於補碼。也就是1091567616

如果以浮點型打印的話也就是9.000000

結語:

寫的很長時間,如果有用就收藏吧

到此這篇關於c語言 數據存儲與原碼 反碼 補碼詳細解析的文章就介紹到這瞭,更多相關c語言 數據存儲內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: