1. 程式人生 > >C語言基本型別與其資料儲存方式

C語言基本型別與其資料儲存方式

好久沒有更新部落格了,最近對逆向十分著迷,資訊保安的知識量是真的龐大,是時候該做一波筆記了,哈哈。

看下圖,C語言資料型別分為右邊四大型別,這篇部落格重點講基本型別,因為其他型別還沒學呢~~

整數型別

資料型別分為 char short int long 四種

char                        8BIT                     1位元組  -----寬度-----> byte

short                       16BIT                     2位元組  -----寬度-----> word

     int                          32BIT                     4位元組  -----寬度-----> dword

     long                       32BIT                     4位元組  ---------------------------

在很多年前的16位計算機上,int型別是佔2個位元組的,到了32位計算機上,int型別變成了4位元組,然而long沒變,原來4位元組,現在還是4位元組,這是個歷史遺留問題,平時我們使用前三個即可。

88:       char a = 0xFF;
0040D608 C6 45 FC FF          mov         byte ptr [ebp-4],0FFh
89:       short b = 0xFF;
0040D60C 66 C7 45 F8 FF 00    mov         word ptr [ebp-8],offset main+20h (0040d610)
90:       int c = 0xFF;
0040D612 C7 45 F4 FF 00 00 00 mov         dword ptr [ebp-0Ch],0FFh
觀察88行程式碼以及對應下一行彙編程式碼,可以發現,當資料型別定義為char型別時,將0xFF放入了一塊byte大小的記憶體(棧)中。

同理,short和int則放入對應的word大小和dword大小的記憶體空間中。
如果從資料寬度的角度講,C語音中的char就是彙編中的byte,short就是彙編中的word,int就是彙編中的dword。

再觀察以下程式碼,注意寬度

88:       char a = 0x12345678;
0040D608 C6 45 FC 78          mov         byte ptr [ebp-4],78h
89:       short b = 0x12345678;
0040D60C 66 C7 45 F8 78 56    mov         word ptr [ebp-8],offset main+20h (0040d610)
90:       int c = 0x12345678;
0040D612 C7 45 F4 78 56 34 12 mov         dword ptr [ebp-0Ch],12345678h
可以發現,0x12345678(32位)可以存到byte裡?word裡?

答案其實很明顯,當然不可以。

除錯程式,觀察記憶體,可以得出以下結果:

[ebp-4] 這記憶體地址,大小byte,存入的結果為   78

[ebp-8] 這記憶體地址,大小word,存入的結果為   78 56

[ebp-0xC] 這記憶體地址,大小dword,存入的結果為   78 56 34 12

Q:為什麼存入記憶體(棧)中時,是按照4位元組4位元組的存呢(-4,-8,-0xC....),而不是按照實際大小存,這樣不是會造成空間浪費嗎?

首先因為它是用堆疊存的,確實是有空間浪費的,但是這樣的定址效率比挨著存會高很多。

其實整數型別分為有符號(signed)和無符號(unsigned)兩種的,上面預設省略的就是有符號的

那麼有符號和無符號有什麼區別呢?這個問題在學習彙編的時候就十分糾結,那麼下面我們來觀察下有符號和無符號在記憶體中是如何存的?

88:       //預設就是有符號
89:       char a = 0xFF;
0040D608 C6 45 FC FF          mov         byte ptr [ebp-4],0FFh
90:       //無符號
91:       unsigned char b = 0xFF;
0040D60C C6 45 F8 FF          mov         byte ptr [ebp-8],0FFh
觀察彙編程式碼,除錯觀察記憶體其實可以知道,不管是有符號還是無符號,在記憶體中是沒有任何區別的,你讓我存什麼,我就存什麼。

其實所謂的有符號與無符號,計算機本身是無辜的,他只是存了一堆數而已。

那我們使用printf函式打印出a和b

//預設就是有符號
char a = 0xFF;
//無符號
unsigned char b = 0xFF;
printf("%d\n",a); // -1
printf("%d\n",b); // 255
計算機記憶體中存了相同的0xFF,為什麼打印出來的結果卻不同呢?

其實如果你把0xFF當有符號來看,那麼就是-1,如果當無符號來說,那麼就是255。所以有符號和無符號,其實就是用的這個人(程式設計師)說了算,同樣是0xFF,有符號就是-1,無符號就是255。

一般有符號與無符號,在大小比較,型別轉換,數學運算這幾種情況我們需要特別注意。

有符號與無符號,在記憶體中儲存的方式完全一樣,只不過在用的時候,你把它當成有符號用,那就是有符號,反之也是一樣。計算機是不管有符號還是無符號,當你是有符號時,他就會生成對應的有符號對應的彙編指令,無符號就會生成無符號對應的彙編指令。

浮點型別

浮點型別通俗點的說就是拿來存小數的,有float和double兩種。

上面的整數型別是會直接轉化為二進位制形式存進去,那麼浮點型在記憶體中是這麼樣子的呢?

88:       int a = 8;
00401298 C7 45 FC 08 00 00 00 mov         dword ptr [ebp-4],8
89:       float b = 8.25;
0040129F C7 45 F8 00 00 04 41 mov         dword ptr [ebp-8],41040000h
可以發現int型別時,其值是0x8,而float型別時,卻是0x41040000,這個數是這麼來的呢?

任何一個整數最後都是可以轉化為二進位制的,那麼小數呢?這個恐怕困難了,下面我們就來講講浮點型的儲存方式。

首先,float和double在儲存方式上都是遵從IEEE的規範的

float的儲存方式如下圖所示:


double的儲存方式如下圖所示:

看不懂上面沒關係,一步步來,我們拿float來講解儲存,double同理即可。

首先,我們需要搞清出下面兩個問題:

(1) 十進位制整數如何轉化為二進位制數

演算法其實只要一直除以2,然後取餘數即可。


(2)十進位制小數如何轉化為二進位制數

演算法是一直乘以2,然後取整數部分即可。


挺簡單的吧,但是如果是十進位制小數 0.8 呢?你會發現出現了死迴圈.....看下圖

那麼很顯然,小數的二進位制表示有時是不可能精確的

好了,弄懂了上面兩個問題,下面來講講將一個float型轉化為記憶體儲存格式的步驟:

  1. 先將這個實數的絕對值化為二進位制格式
  2. 將這個二進位制格式實數的小數點左移或右移n位,直到小數點移動到第一個有效數字的右邊
  3. 從小數點右邊第一位開始數出二十三位數字放入第22到第0位
  4. 如果實數是正的,則在第31位放入“0”,否則放入“1”
  5. 如果n 是左移得到的,第30位放入“1”。如果n是右移得到的或n=0,則第30位放入“0”
  6. 將n減去1後化為二進位制,不足七位則在左邊加“0”補足七位,超7位則取後七位,放入第29到第23位。

正實數轉化

拿 浮點數8.25 儲存 來舉例說明

第一步 8.25絕對值轉化為二進位制,看懂了上面的轉換那就很簡單了,那麼:

8.25用二進位制表示可表示為 1000.01

第二步 簡單的說就是將其二進位制使用科學記數法來表示,左移一位乘2,右移一位除2,那麼


第三步 將[00001000000000000000000] 放入第22到0位,結果如下圖:


第四步 很明顯,31位應該放入 0,結果如下圖:


第五步 這個也比較明顯,左移,指數為3,那麼第30位存的是 1,結果如下圖:

第六步 將指數(3) - 1 = 2 ,轉化為二進位制就是 10,左邊加0補齊7位(上一步佔了一位,所以7位),結果就是 0000010

好了,正實數轉化為二進位制就到此就結束了,那麼我們將其轉化為16進位制結果驗證一下。

將其4位4位分割,最終轉化為十六進位制值是:0x41040000

89:       float b = 8.25;
00401298 C7 45 FC 00 00 04 41 mov         dword ptr [ebp-4],41040000h
沒錯,看彙編程式碼中也是0x41040000,說明我們轉化為二進位制是正確滴。

再舉一個例子,浮點數0.25是如何儲存的呢?(若是看懂了上面的例子,那麼這個也就容易理解了)

第一步 轉化為二進位制後結果:

0.25用二進位制表示可表示為 0.01

第二步 科學記數法表示,右移兩位


第三步 這個很明視訊記憶體的都是0,第四步 由於是正數,所以存的也是 0,第五步 由於是右移,所以存的也是 0。結果如下圖


第六步 指數(-2) - 1 = -3,-3的二進位制是如何表示呢?看如下程式碼

十進位制   十六進位制  二進位制
-1        0xFF    11111111
-2        0xFE    11111110
-3        0xFD    11111101
取其後七位(1111101)放入29到23位,結果如下:

將其轉化為十六進位制進行驗證,其轉化十六進位制結果為:0x3E800000

89:       float b = 0.25;
00401298 C7 45 FC 00 00 80 3E mov         dword ptr [ebp-4],3E800000h
比較其彙編結果,可以發現其轉換是正確滴

負實數轉化

就拿 -1.8 來舉例吧,這個有點難受~,數字有點長呀

第一步 將其絕對值轉化為二進位制,由上面可知,0.8轉化二進位制是沒有精確值的哦

1.8用二進位制可表示為 1.11001100110011001100110011001100...

第二步 正好不用移,用科學記數法表示為:


第三步 從小數點後開始取23位放入尾數部分


第四步 負數,符號位放入 1

第五步 由於n(n是科學記數法表示時需要左移或右移的位數,根據第二步可得無移動) 等於0,所以第30位是0

最後一步 0(指數) - 1 = -1,轉化為二進位制為 11111111,取其後七位

將其轉化為十六進位制

1011 1111 1110 0110 0110 0110 0110 0110
 B    F    E    6    6    6    6    6

其二進位制轉化為十六進位制為:0xBFE66666
使用VC++ 6.0執行除錯,觀察其彙編程式碼驗證
89:       float b = -1.8;
00401298 C7 45 FC 66 66 E6 BF mov         dword ptr [ebp-4],0BFE66666h
嘿嘿,結果正確~

相關推薦

C語言基本型別與其資料儲存方式

好久沒有更新部落格了,最近對逆向十分著迷,資訊保安的知識量是真的龐大,是時候該做一波筆記了,哈哈。 看下圖,C語言資料型別分為右邊四大型別,這篇部落格重點講基本型別,因為其他型別還沒學呢~~ 整數型別 資料型別分為 char short int long 四種 char 

11.1 js中級,資料型別資料儲存方式、作用域記憶體空間的區別以及例識別。

一. 基本資料型別和引用資料型別的區別。     1.基本資料型別:基本資料型別就是簡單的操作值。     2.引用資料型別:就是把引用的地址賦給變數。   堆記憶體:     就是存放程式碼塊的,存放形式有兩種       1)物件以鍵值對的形式存放       2)引用資料型別的賦值,是把引用

C語言基本型別

32位平臺下 C語言基本型別: 整型(int):4 位元組 取值:-231 ~ (231 - 1) 短整型(short):2 位元組 取值 :-215 ~ (215 - 1) 長整型(long):4 位元組 取值:-231 ~ (231 - 1) 浮點型 單精度型(float):4 位元組

C語言基礎--指標和資料儲存

資料的訪問方式: ------------------------------------ 直接訪問:直接訪問記憶體單元中的內容 間接訪問:通過 記憶體單元編號 或者 資料所佔位元組點數 訪問記憶體

5. C語言基本資料型別及構造資料型別,浮點型儲存規則及記憶體模型

  其實學習C語言的時候有一件很頭疼的事就是各種各樣的資料型別,不同的場合不同的用途不同的資料要使用不同的資料型別,那又為什麼要分出這麼多種型別呢,因為型別決定了開闢空間的大小,開闢空間的大小又決定了儲存的範圍。今天,就資料型別這個問題我們來掰扯掰扯。   C

C語言變數定義與微控制器資料儲存方式

說明:文章來源 EDN電子技術設計:嵌入式程式開發需要知道的儲存器知識 MCU 中常使用的儲存器型別有:FLASH、RAM、ROM(包括EEPROM) 在軟體角度來看,程式和資料的儲存分為以下幾個部分 程式碼段和常量段都可以用於儲存常量資料,其主要區

C語言基本資料型別short、int、long、char、float、double

1.概述  C 語言包含的資料型別如下圖所示2.各種資料型別介紹2.1整型  整形包括短整型、整形和長整形。2.1.1短整形  short a=1;2.1.2整形  一般佔4個位元組(32位),最高位代表符號,0表示正數,1表示負數,取值範圍是-2147483648~2147

c語言基本資料型別所佔的位數

1.C++的short、int、long和long long型別通過使用不同數目的位來儲存值,最多能夠表示4中不同的整數寬度。C++提供了一種靈活的標準,它確保了最小長度(從C語言借鑑而來),如下: 1. short 至少16位 2. int 至少與 short 一樣長 3

C語言基本資料型別簡介

1.概述   C 語言包含的資料型別如下圖所示: 2.各種資料型別介紹 2.1整型   整形包括短整型、整形和長整形。 2.1.1短整形   short a=1; 2.1.2整形   一般佔4個位元組(32位),最高位代表符號,0表示正數,1表示負數,取值範圍是-2147483648~2147483647

C語言基本資料型別

一,整型   char    short    int  long      、long long(C99新加入),再與unsigned搭配,共有10種類型 c,八進位制和十六進位制的整數常量(無負數) 234u,234, 在C語言中預設的數字為十進位制。如果在一個數字前面

C語言基本資料型別對應位元組大小及printf函式輸出格式

補充說明:4位元組:int(%d),unsigned=unsigned int(%u),long=long int(%ld),unsigned long(%lu),float(%f)8位元組:double(%lf),unsigned long long(%llu),long

C語言程式設計入門之--第四章C語言基本資料型別

    導讀:C語言程式中經常涉及一些數學計算,所以要熟悉其基本的資料型別。資料型別學習起來比較枯燥,不過結合之前的記憶體概念,以及本節的位元組概念,相信資料型別也就不難理解了。本章從二進位制的基本概念開始,然後介紹機器語言通用的計算單位位元組,最後再介紹C語言中基本的資料型別及其基本概念。 &

C語言第三天-資料型別,if switch,for while

背會!!! 格式字元有d,o,x,u,c,s,f,e,g等。  如 %d整型輸出,%ld長整型輸出, %o以八進位制數形式輸出整數, %x以十六進位制數形式輸出整數,或輸出字串的地址。 %u以十進位制數輸出unsigned型資料(無符號數)。注意:%d與%u有無符號的數

C語言中有關於資料型別的幾個問題

1.整型資料轉換成字元型資料時資料過大; int  ch1 = 5566; char  ch2 = (char)ch1; printf("%c \n", ch2 ); 輸出亂碼�;char型別最大範圍到127,所以ch1最大隻能到127。 2.int  ch1 =

C語言ADT(抽象資料型別程式設計)

C語言是一種計算機程式設計語言。它既具有高階語言的特點,又具有組合語言的特點。它可以作為工作系統設計語言,編寫系統應用程式,也可以作為應用程式設計語言,編寫不依賴計算機硬體的應用程式。因此,它的應用範圍廣泛,不僅僅是在軟體開發上,而且各類科研都需要用到C語言,具體應用比如

C語言基本資料結構之二(二叉樹的三種遍歷,節點數以及深度演算法)

關於二叉樹的定義,網上有比較好的介紹,在這裡就簡單介紹二叉樹的一些性質 二叉樹的基本性質 1)二叉樹的第i層上至多有 2^(i-1)(i ≥1)個結點; 2)深度為 h 的二叉樹中至多含有 2^h – 1 個結點; 3)若在任意一棵二叉樹中,有 n0 個葉子結點,有 n2

c語言常量變數和資料型別

常量:在程式執行過程中不被改變的量。 變數:在程式執行過程中可以被改變的量。 變數定義: 資料型別 變數名 = 常量;(初始化) 定義性宣告: 資料型別 變數名; 變數命名規則: 1、數字、字母、下劃線都可做變數名; 2、變數名的開頭不能為數字

c語言-變數的四種儲存型別

auto         自動變數register     暫存器變數extern 外部變數static 靜態變數 一般形式:儲存型別說明符 資料型別說明符 變數名,變數名...static int a,b; auto char c1,c2; static int a[3

單鏈表基本操作的C語言實現(鏈式儲存結構)

#include<stdio.h> #include<stdlib.h> typedef int DataType; typedef struct Node{ DataType data; struct Node *next; }

C語言中的四種儲存型別

   一、 首先來說說資料的型別,所有的資料都有兩種型別,一是常見的資料型別,如int,float等,一種便是今天的重頭戲,儲存型別。總共有四種儲存型別的變數,分別為自動變數(auto)、靜態變數(s