首頁 > 軟體

c語言 資料儲存與原碼 反碼 二補數詳細解析

2022-02-10 19:00:30

前言

學習本章你會了解:

1.資料型別詳細介紹

2.整形在記憶體中的儲存:以及瞭解原碼、二補數、反碼

3.大小端位元組序的介紹和判斷

4.浮點型在記憶體中的儲存解析

1.資料的型別介紹

在學習資料儲存之前,讓我們先認識一下資料型別。以下這些資料型別是我們初學c語言時的基礎型別以及大小所佔位元組數。

比如所佔位元組數型別
char1//符資料的型別
shot2//短整型
int4//整形
long (規定sizeof(long)>=sizeof(int) )4//長整型
long long(部分編譯器不支援)8//更長的起整數
float4//單精度浮點數
double8//雙精度浮點數

還有構造型別:

陣列型別

結構體型別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(%un",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的值為:%dn",n);
printf("*pFloat的值為:%fn",pFloat);
*pFloat=9.0;
printf("num的值為:%dn",n);
printf("*pFloat的值為:%fn",*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語言 資料儲存內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com