網站首頁 編程語言 正文
前言
學習本章你會了解:
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
相關推薦
- 2022-02-21 MyBatis There is no getter for property named ‘xxx
- 2023-01-15 PyQt5+QtChart繪制散點圖_python
- 2022-10-31 解決Python3中二叉樹前序遍歷的迭代問題_python
- 2022-11-30 C語言中順序棧和鏈棧的定義和使用詳解_C 語言
- 2023-03-01 Shell腳本read用法實現_linux shell
- 2022-04-12 如何在Python中編寫接口和請求外部接口_python
- 2022-08-11 boost字符串處理函數format的用法_C 語言
- 2022-01-19 正則表達式匹配日期格式yyyy-mm-dd(支持閏年)
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支