日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

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

作者:誠摯的喬治 ? 更新時間: 2022-04-16 編程語言

前言

學習本章你會了解:

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

結語:

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

原文鏈接:https://z-ming.blog.csdn.net/article/details/121994434

欄目分類
最近更新