<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
C語言中存在著資料型別,我們或多或少都見到過。
char //字元資料型別 - 1個位元組
short //短整型 - 2個位元組
int //整形 - 4個位元組
long //長整型 - 4/8個位元組
long long //更長的整形 - 8個位元組
float //單精度浮點數 - 4個位元組
double //雙精度浮點數 - 8個位元組
小思考:C語言有沒有字串型別?
C語言有字串,表示為"字串內容"的形式,但不存在字串型別。
型別存在的意義是什麼?
整形
char
unsigned char
signed char
//雖然是字元型別,但是字元型別儲存的時候,儲存的字元的ascii碼值,ascii碼值是整數
short
unsigned short [int]
signed short [int]
int
unsigned int
signed int
long
unsigned long [int]
signed long [int]
unsigned 和 signed
Tips:
對於short,int,long,long long資料在進行定義時,預設都為signed。而對於char型別則不確定,C語言標準沒有規定char是否有符號,取決於編譯器,所以char實際上可以歸為3類,char(不確定),signed char(有符號),unsigned char(無符號)。在vs2022中,char預設為signed char。
浮點型
float//單精度浮點數 - 4個位元組
double//雙精度浮點數 - 8個位元組
構造型別
//例:int arr[10]
陣列型別 int [10]
//陣列只要個數和元素型別發生變化,型別都會發生變化
結構體型別 struct
列舉型別 enum
聯合型別 union
指標型別
int *pi;//整形指標
char *pc;//字元指標
float* pf;//單精度浮點數指標
void* pv;//空型別指標
空型別
void 表示空型別(無型別)
通常應用於函數的返回型別、函數的引數、指標型別。
例:
void test1()//無返回值 {} void test2(void)//函數接收引數,引數部分加void {} int main() { void* p = NULL; //void*可以存放任何型別的指標 int a = 10; void* p1 = &a;//沒問題 p1++;//err,不知道型別,無法決定跳過幾個位元組 *p1;//err,不知道型別,無法決定解除參照的許可權 //一般用來臨時存放地址,用的時候拿走或者強轉使用 return 0; }
一個整形變數的建立需要再記憶體中開闢四個位元組,那整形在記憶體中是如何儲存的?
比如:
int a = 10;
int b = -10;
在瞭解整形在記憶體中如何儲存之前我們需要了解以下概念:
計算機中的整數有三種2進位製表示方法,即原碼、反碼、二補數。
三種表示方法均有符號位和數值位兩部分,二進位制序列的第一位為符號位,其他均為數值位,符號位數值位均由0,1組成。
原碼:
直接將數值按照正負的形式翻譯成二進位制就可以。
反碼:
原碼的符號位不便,其他位依次按位元取反就可以得到。
二補數:
反碼 + 1得到二補數。
注意:
樣例:
int a = 10;//整形值 //0000 0000 0000 0000 0000 0000 0000 1010 a的原、反、補 //轉化為16進位制:0X0000000a int b = -10;//整形值 //1000 0000 0000 0000 0000 0000 0000 1010 b的原碼 //1111 1111 1111 1111 1111 1111 1111 0101 b的反碼 //1111 1111 1111 1111 1111 1111 1111 0110 b的二補數 //轉化為16進位制:0Xfffffff6
那麼對於整形而言,在記憶體中儲存的是什麼呢?
讓我們啟動偵錯,檢視記憶體:
我們可以看到對於a和b分別儲存的是二補數,這是為什麼?
在計算機系統中,數值一律用二補數來表示和儲存。原因在於,使用二補數,可以將符號位和數值域統一處理;
同時,加法和減法也可以統一處理(CPU只有加法器)此外,二補數與原碼相互轉換,其運算過程是相同的,不需要額外的硬體電路。
舉個簡單的例子,例如計算機在計算a - b的時候,會轉化成a + (-b)的形式進行計算,而這時使用原碼來進行計算,是無法計算出結果的,但使用二補數就可以計算出結果。
但是對於資料在記憶體中儲存的方式很奇怪,它是倒著儲存的,這是為什麼?讓我們瞭解一下大小端。
什麼是大端小端:
大端位元組序儲存:把一個資料低位位元組處的資料存放在高地址處,把高位位元組處的資料放在低地址處
小端位元組序儲存:把一個資料低位位元組處的資料存放在低地址處,把高位位元組處的資料放在高地址處。
例如:
0x11223344
為什麼會有大端和小端:
為什麼會有大小端模式之分呢?這是因為在計算機系統中,我們是以位元組為單位的,每個地址單元都對應著一個位元組,一個位元組為8 bit。但是在C語言中除了8 bit的char之外,還有16 bit的short型,32 bit的long型(要看具體的編譯器),另外,對於位數大於8位元的處理器,例如16位元或者32位元的處理器,由於暫存器寬度大於一個位元組,那麼必然存在著一個如何將多個位元組安排的問題。因此就導致了大端儲存模式和小端儲存模式。
例如:一個16bit 的short 型x ,在記憶體中的地址為0x0010 , x 的值為0x1122 ,那麼0x11 為高位元組, 0x22 為低位元組。對於大端模式,就將0x11 放在低地址中,即0x0010 中, 0x22 放在高地址中,即0x0011 中。小端模式,剛好相反。我們常用的X86 結構是小端模式,而KEIL C51 則為大端模式。很多的ARM,DSP都為小端模式。有些ARM處理器還可以由硬體來選擇是大端模式還是小端模式。
其實資料在記憶體中無論是大小端儲存或者亂序儲存都可以,大小端位元組序儲存也是為了讓儲存方式變得更簡單,如果亂序儲存的話在還原資料時會更加複雜。
注:大小端儲存時以位元組為單元,16進位制的兩位為一個位元組,為一個單元,按照大小端儲存規律儲存,並不會將16進位制的每一位都倒過來儲存。例如0x123456按照小端儲存就為56 34 12 00,而不是65 43 21 00。
所以說大小端位元組序儲存,就是以位元組為單位的儲存順序。
一道筆試題
請簡述大端位元組序和小端位元組序的概念,設計一個小程式來判斷當前機器的位元組序。
思路:資料在記憶體中是通過二補數的形式儲存的,判斷大端還是小端,例如數位1,我們只需要觀察它的第一個位元組為0或1,就可以判斷位元組序。而資料型別決定了指標解除參照時看待記憶體的視角,所以我們可以用char*
指標來對元素第一個位元組的內容進行解除參照。
int check_sys() { int a = 1; //二進位制:0000 0000 0000 0000 0000 0000 0000 0001 //十六進位制:0x00000001 char* p = (char*)&a;//char*指標解除參照為一個位元組 if (*p == 1) return 1; else return 0; } //簡化 //int check_sys() //{ // int a = 1; // return *(char*)&a;//1的大端或小端儲存,第一位為00或者01,取出的值正好和main函數中接收的值相同,直接返回 //} int main() { int ret = check_sys(); if (ret = 1) { printf("小端n"); } else { printf("大端n"); } }
char在記憶體中儲存的是字元的Ascii碼值,所以也歸於整形。但是它的取值範圍和整形不同。
char型別變數的大小為1個byte,也就是8個bit位,對於char型別,我們分signed和unsigned兩塊進行講解。
signed:
signed為有符號字元型別,二進位制序列的第一位為符號位,其他位為資料位,取值範圍為-128 ~ 127.
unsigned:
unsigned為無符號字元型別,二進位制序列全為資料位,取值範圍為0 ~ 255.
圖例:
下列程式的輸出結果是什麼?
int main() { char a = -1; //整形提升 //1000 0000 0000 0000 0000 0000 0000 0001 //1111 1111 1111 1111 1111 1111 1111 1110 //1111 1111 1111 1111 1111 1111 1111 1111 //截斷:1111 1111 //整形提升 //1111 1111 1111 1111 1111 1111 1111 1111 - 二補數 //1000 0000 0000 0000 0000 0000 0000 0000 //1000 0000 0000 0000 0000 0000 0000 0000 - 原碼 //-1 signed char b = -1; //求解過程和a相同 unsigned char c = -1; //截斷:1111 1111 //無符號字元,整形提升,高位補0 //0000 0000 0000 0000 0000 0000 1111 1111 - 二補數==原碼 //截斷:1111 1111 printf("a=%d,b=%d,c=%d", a, b, c);//-1,-1,255 //當列印a,b,c時,要整形提升 return 0; }
執行結果:
下列程式的輸出結果是什麼?
int main() { char a = -128; //1000 0000 0000 0000 0000 0000 1000 0000 //1111 1111 1111 1111 1111 1111 0111 1111 //1111 1111 1111 1111 1111 1111 1000 0000 //截斷:1000 0000 //%u - 指的是列印無符號整數 //整形提升 //有符號字元,補符號位 //1111 1111 1111 1111 1111 1111 1000 0000 - 要列印原碼,而這是無符號數,所以這個就是原碼 printf("%un", a);//4294967168 return 0; }
執行結果:
下列程式的輸出結果是什麼?
int main() { char a = 128; //0000 0000 0000 0000 0000 0000 1000 0000 //1111 1111 1111 1111 1111 1111 0111 1111 //1111 1111 1111 1111 1111 1111 1000 0000 //截斷1000 0000 //整形提升 //有符號字元,補符號位 //1111 1111 1111 1111 1111 1111 1000 0000 - 原碼 printf("%un", a);//? return 0; }
執行結果:
下列程式的輸出結果是什麼?
int main() { int i = -20; //1000 0000 0000 0000 0000 0000 0001 0100 - 原碼 //1111 1111 1111 1111 1111 1111 1110 1011 - 反碼 //1111 1111 1111 1111 1111 1111 1110 1100 - 二補數 unsigned int j = 10; //0000 0000 0000 0000 0000 0000 0000 1010 - 二補數 printf("%dn", i + j);//-10 //i + j //1111 1111 1111 1111 1111 1111 1111 0110 - 二補數 //列印有符號整形,轉化成原碼 //1000 0000 0000 0000 0000 0000 0000 1001 //1000 0000 0000 0000 0000 0000 0000 1010 - 原碼 return 0; }
執行結果:
下列程式的輸出結果是什麼?
int main() { unsigned int i;//恆大於0 for (i = 9; i >= 0; i--)//死迴圈 { printf("%un", i); //9 ~ 0 ~ 超大的值:-1的二補陣列成的迴圈 //-1的二補數:1111 1111 1111 1111 1111 1111 1111 1111 //放到無符號整數中,將-1的二補數直接當做原碼輸出 //得到超大的值 Sleep(1000);//程式停止一秒 } return 0; }
執行結果:
下列程式的輸出結果是什麼?
int main() { char a[1000]; int i; for (i = 0; i < 1000; i++) { a[i] = -1 - i; //char取值範圍-128 ~ 127 //當a[i]的值小於-128時,會轉化成127並大於0的值,當a[i]=0時, //' '的ascii碼值為0,當strlen進行計算時,計算第一個' '前的字元個數 //陣列中元素:-1 , -2 , ... ,-128 , 127, ..., 1, 0... } printf("%d", strlen(a)); //求' '前字元的個數 //' '的ascii碼值為0 }
圖解:
執行結果:
下列程式的輸出結果是什麼?
unsigned char i = 0;//0 ~ 255 int main() { int i = 0; //0 ~ 255為區間,迴圈進行這個區間,列印hello world for (i = 0; i <= 255; i++)//死迴圈 { printf("hello worrldn"); } }
執行結果:
到此這篇關於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