<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
大家肯定經常聽說記憶體這個詞,記憶體到底是什麼呢? 在計算機中,程序都要載入進記憶體中,也是我們各種資料的流通途徑,C語言中,大家肯定都知道指標變數,指標變數中儲存的就是記憶體的地址,那麼,什麼是記憶體的地址呢?
記憶體的單位是位元組
對於32位元的機器,有32根地址線,每根地址線在定址時,產生的高低電壓分別為0/1,那麼32根地址線產生的地址就會是
00000000000000000000000000000000
00000000000000000000000000000001
00000000000000000000000000000010
…
11111111111111111111111111111111
這裡就有2^32次方個地址
大家應該知道,還有64位元的機器,64根地址線又有多少個地址呢,大家可以計算一下
在32位元的機器上,地址是32個0或者1組成二進位制序列,那地址就得用4個位元組的空間來儲存,
所以一個指標變數的大小就應該是4個位元組。 那如果在64位元機器上,有64個地址線,那一個指標變數的大小是8個位元組,才能存放一個地址。
這串編號就是記憶體單元的地址,就像酒店的房間號一樣,對應著記憶體中的一個位元組大小的房間
我們在vs中來看一下
這裡是以十六進位制的方式展示的,大家也知道,32個數位看起來太長了。
關於c語言中的資料型別,大家在寫了這麼多程式碼後肯定也很清楚了,C語言中有整型、浮點型、字元型、等等
我們來研究一下整數在記憶體中是如何儲存的
大家都知道,定義變數,會在記憶體中開闢空間來儲存
int a = 20;
int型別在vs中佔據4個位元組的空間,那麼如何儲存呢?
這就涉及到原碼反碼二補數的概念
原碼:
直接將數值按照正負數的形式翻譯成二進位制就可以得到原碼
反碼:
將原碼的符號位不變,其他位依次按位元取反就可以得到反碼
二補數:
反碼+1就得到二補數。
對於整型變數來說,記憶體中存放的其實是二補數
使用二補數,可以將符號位和數值域統一處理,加法和減法也可以同一處理,因為CPU只有加法器
eg:
int a = 20; //原碼 : 直接寫二進位制 00000000000000000000000000010100 //反碼--二補數 -- 正數的原反補相同 int b = -5; //原碼: 10000000000000000000000000000101 //反碼:符號位不變,按位元取反 // 11111111111111111111111111111010 //二補數:反碼+1 // 11111111111111111111111111111011 -- -5的二補數
上邊可以看見-5的二補數是11111111111111111111111111111011 ,我們如何確認呢?
轉換成16進位製為fffffffb
大家可以看到確實是使用二補數儲存的,但是為什麼是倒著儲存的,後邊再來說,這是由於大小端的問題
給大家舉幾個例子,不知道儲存無法分析出結果程式碼
//1. #include <stdio.h> int main() { char a = -128; printf("%un",a); //-128 原碼: 10000000 00000000 00000000 10000000 //-128 反碼: 11111111 11111111 11111111 01111111 //-128 二補數: 11111111 11111111 11111111 10000000 //存在a裡面的,因為只有一個位元組 10000000 //所以會當做無符號整數列印 --整形提升 //提升為 11111111111111111111111110000000 //所以結果是一個很大的整數,大家可以嘗試一下 return 0; }
#include <stdio.h> int main() { char a = 128; //128的原碼反碼二補數 : 00000000000000000000000010000000 //存在a裡的:10000000 //整形提升 :11111111111111111111111110000000 //所以結果還是那個很大的整數 printf("%un",a); return 0;
例子就簡單給大家舉到這裡,大家一定要記住整數在記憶體中是以二補數的形式儲存的
字元儲存的是ASCII碼,所以和整數同
我們來看一下浮點數在記憶體中的儲存
拋磚引玉:
#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; }
上面程式碼的列印結果到底是什麼呢?
是不是非常出乎大家的意料呢,這裡就可以看出,浮點數的儲存肯定和整數是不同的。那浮點數到底咋存的呢?
根據國際標準IEEE(電氣和電子工程協會) 754,任意一個二進位制浮點數V可以表示成下面的形式:
看得很迷糊,直接上例子
v = 5.5
= 101.1 --二進位制表示
= 1.011 * 2 ^2 – 科學記數法表示
因為是正數 s = 0
m = 1.011
e = 2
IEEE 754規定:
對於32位元的浮點數,最高的1位是符號位s,接著的8位元是指數E,剩下的23位為有效數位M。
IEEE 754對有效數位M和指數E,還有一些特別規定
1=<M <2 ,所以M可以寫成1.xxxxx 所以可以捨去1 ,只儲存xxxxxx
IEEE 754規定,在計算機內部儲存M時,預設這個數的第一位總是1,因此可以被捨去,只儲存後面的xxxxxx部分。比如儲存1.01的時候,只儲存01,等到讀取的時候,再把第一位的1加上去。這樣做的目的,是節省1位有效數位。以32位元浮點數為例,留給M只有23位,將第一位的1捨去以後,等於可以儲存24位元有效數位
對於指數E,E是一個無符號整數,但是科學記數法指數是可以出現負數的,所以
IEEE 754規定了偏移量,如果E為8位元,則加上127 ,如果E為11位,則加上1023
我們舉個例子
float f = 8.5f;
//二進位制 : 1001.1
//科學計數法表示: 1.0011*2^3
//S = 0 M = 1.0011 E = 3
//儲存進去的應該是:
0 10000010 00110000000000000000000
//我們可以驗證一下
轉換成16進位制
0100 0001 0001 1000 0000 0000 0000 0000
//41 18 00 00
我們來看一下程式碼
和我們想的一樣
我們再來舉一個負數的例子
float t = -3.5f;
//二進位制: 11.1
//科學記數法: 1.11*2^1
//S = 1 M = 1.11 E = 1
//儲存:
1 10000000 11000000000000000000000
//轉換成16進位制
1100 0000 0011 0000 0000 0000 0000 0000
c0 60 00 00
那我們從記憶體中讀取出來的二進位制位如何解析成浮點數呢
關於E,有三種情況
E不全為0或不全為1
這時,浮點數就採用下面的規則表示,即指數E的計算值減去127(或1023),得到真實值,再將有效數位M前加上第一位的1
2.E全為0
這時,浮點數的指數E等於1-127(或者1-1023)即為真實值,
有效數位M不再加上第一位的1,而是還原為0.xxxxxx的小數。這樣做是為了表示±0,以及接近於 0的很小的數位。
3.E全為1
這時,如果有效數位M全為0,表示±無窮大(正負取決於符號位s);
我們來分析一下最開始的題目
浮點數和整數的儲存就介紹到這裡了,有哪裡不清楚的朋友可以私信我
上邊有一個懸念,為什麼是倒序儲存的
那什麼是大端小端呢?
大端(儲存)模式: 資料的低位儲存在記憶體的高地址中,資料的高位儲存在記憶體的低地址中
小端(儲存)模式: 資料的低位儲存在記憶體的低地址中,資料的高位儲存在記憶體的高地址中
那為什麼會有大小端呢?
記憶體中以位元組為單位,但是比如int 是4個位元組,那如何安排這個4個位元組呢?就導致了大小端儲存模式
例如:一個 16bit 的 short 型 x ,在記憶體中的地址為 0x0010 , x 的值為 0x1122 ,那麼 0x11 為高位元組, 0x22 為低位元組。對於大端模式,就將 0x11 放在低地址中,即 0x0010 中, 0x22 放在高地址中,即 0x0011 中。小端模式,剛好相反。我們常用的 X86 結構是小端模式,而 KEIL C51 則 為大端模式。很多的ARM,DSP都為小端模式。有些ARM處理器還可以由硬體來選擇是大端模式 還是小端模式。
那我們如何測試當前電腦是哪種儲存模式呢?
int main(void) { int a = 0x11223344; return 0; }
我們偵錯開啟記憶體看一下
很明顯,資料的低位儲存在記憶體低地址中,所以為小端儲存模式。
我們能不能寫一個程式,直接告訴我們大小端呢?
我們來分析一下
我們來看一下程式碼
int decide_byte_orde() { int i = 1; return *(char *)&i; }
我們來測試一下
深入理解資料的儲存是非常有必要的,我們之後碰到很多問題都會豁然開朗,大家一定要好好研究一下
到此這篇關於C語言中資料如何儲存揭祕的文章就介紹到這了,更多相關C語言資料儲存內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45