摘要:外部設備會自己處理字節序的問題。本地序和網絡序從前面對于字節序的介紹可以知道采用小端序,而等采用大端序。協議很好的解決了這個問題,協議規定使用大端字節序作為網絡字節序。提供了一組接口用于整型數據在本地序和網絡序之間的轉換。
我們學習了整型在內存中是以原反補碼的形式存儲的,我們還學習了浮點型在內存中是以符號位(S)指數位(E)有效數字(M)的形式存儲的。
那么我們知道了數據在內存中是以什么樣的形式存儲的,可是我們知道內存中有高地址有低地址,數據是一個字節分配一個地址,可是僅
char
類型是一個字節,其他類型大都大于一個字節的大小,那么大于一個字節的數據是從【高地址】往【低地址】存放還是從【低地址】往【高地址】存放呢?
舉一個栗子?:當你聲明一個變量的時候,操作系統會給你分配一塊空間,但是如果你創建的這個變量的類型是【short/int/float/double】這些大小大于一個字節的類型的數據,操作系統反正是已經把這些類型相應的大小的空間分配給你了,你內部怎么存儲可不關它的事了,也就是我們將一個4字節的數據存入分配好的一段4字節的物理容器里, 該怎么存放呢?這時,我們存放進去的數據的字節是該依據一般人們的讀寫習慣從左往右依次寫入, 還是從右向左寫入呢? 不論哪種方式只要保證寫入和讀出的數據一致即可。
對于字節序列的存儲格式,必然需要說到CPU的兩大派系,那就是IBM的Power PC系列的CPU和Intel的x86系列的CPU。Power PC系列采用big endian方式存儲數據,而x86系列則采用little endian方式存儲數據。那么big endian和little endian都是些什么鬼呢??
在幾乎所有的機器上,多字節對象都被存儲為連續的字節序列,而字節序指的是多字節的數據各字節在內存中的存儲順序,分為大端存儲模式(Big-Endian)和小端存儲模式(Little-Endian)。
假設,一個4字節的int類型變量a,它的十六進制形式為0x11223344,(0x11
為高位字節,0x44
為低位字節)操作系統分配的空間的起始地址為0x000001,那么a的四個字節將被分別存在0x000001,0x000002,0x000003,0x000004的位置。
顯然,Big-Endian的存儲更貼切于我們平時的讀寫習慣。那么為什么不統一使用Big-Endian呢?
計算機電路先處理低位字節,效率比較高,因為計算都是從低位開始的,所以,計算機的內部處理都是小端字節序。
而大端序存儲,由于符號位在高位,因此對于數據正負或大小的判斷也就方便許多。另外,大端序也更符合人們的讀寫習慣。所以,除了計算機的內部處理,其他的場合幾乎都是大端字節序,比如網絡傳輸和文件儲存。
這里需要注意?:只有讀取的時候,才必須區分字節序,其他情況都不用考慮。
處理器讀取外部數據的時候,必須知道數據的字節序,將其轉成正確的值。然后,就正常使用這個值,完全不用再考慮字節序。即使是向外部設備寫入數據,也不用考慮字節序,正常寫入一個值即可。外部設備會自己處理字節序的問題。
從前面對于字節序的介紹可以知道x86采用小端序,而Power Pc等采用大端序。那么顯然不同的處理器體系,采用的字節序可能是不同的。那么如此一來,不同機器之間的數據傳輸豈不是會出現問題?
本地序(也稱主機序):指處理器本身所采用的字節序,因此有的大端序,有的小端序。
網絡序:指網絡傳輸采用的字節序。網絡序是標準化的,統一采用大端序。因此,發送網絡數據之前需要將本地序轉換為網絡序。
為什么要注意本地序和網絡序的問題呢?當然,如果你寫的程序只在單機環境下面運行,并且不和別人的程序打交道,那么你完全可以忽略字節序的存在。但是,你的程序是要跟別人的程序產生交互的!
計算機網絡的出現讓大小端問題變的復雜化了,每個計算機都有自己的主機字節序。不同計算機之間通過網絡通信時:我“說”的你聽不懂,你“說”我也聽不懂,這可怎么辦?這時候就需要約定俗成的協議來解決問題。
TCP/IP協議很好的解決了這個問題,TCP/IP協議規定使用“大端”字節序作為網絡字節序。
這樣不管計算機采用哪種字節序,發送數據的時候必須將自己的主機字節序轉換為網絡字節序,對接收到的數據轉換為自己的主機字節序。這樣一來,也就達到了與CPU、操作系統無關,實現了網絡通信的標準化。
數據從本地傳輸到網絡,需要轉換為網絡序,接收到的網絡數據需要轉換為本地序后使用。C提供了一組接口用于整型數據在本地序和網絡序之間的轉換。
通信時的本地序和網絡序之間相互轉換這種常用的操作在Socket API這一層,一般都提供了封裝好的轉換函數。從主機字節序到網絡字節序的轉換函數:htons、htonl(C語言),從網絡字節序到主機字節序的轉換函數:ntohs、ntohl(C語言)。當然,明白了原理后也可以編寫自己的轉換函數。
請簡述大端字節序和小端字節序的概念,設計一個小程序來判斷當前機器的字節序(百度筆試題)
思路:假設給上int a = 1;
1在內存中16進制表示形式為0x 00 00 00 01
,那么這段數據如果按大小端放置:
大端:00 00 00 01
小端:01 00 00 00
可以看出,可以通過判斷第一個字節的內容判斷大小端,第一個字節為0則是大端,為1則是小端。
可是怎么取第一個字節呢?這里我們可以用指針的類型的解引用來控制訪問內存的大小,char*
就是只訪問一個字節的內存。
int main(void){ int a = 1; char* p = (char*)&a; if (*p == 1) printf("小端"); else printf("大端"); return 0;}
把這個功能封裝成一個函數:
int check_system(){ int a = 1; char* p = (char*)&a; if (*p == 1) return 1;//返回1,小端 else return 0;//返回0,大端}
那么這個函數呢,是可以優化的:
int check_system(){ int a = 1; char* p = (char*)&a; return *p; }
仍可以更簡潔:
int check_system(){ int a = 1; return *(char*)&a;}
總結:訪問內存就需要考慮到指針。
#include int main(){ int a = 0x11223344; char *pc = (char*)&a; *pc = 0; printf("%x/n", a); return 0;}
假設a變量的地址為0x64,則a變量在內存中的模型為:
char*類型的指針變量pc只能指向字符類型的空間,如果是非char類型的空間,必須要將該空間的地址強轉為char*類型。
pc實際指向的是整形變量a的空間,即pc的內容為0x64,即44;*pc=0,即將44位置中內容改為0,修改完成之后,a中內容為:0x11223300
(全劇終)感謝食用!
注:參考文章(https://www.ruanyifeng.com/blog/2016/11/byte-order.html)
|
|(系列持續周更)
|
數據存儲系列往期回顧:
詳解浮點型在內存中的存儲
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/119678.html
摘要:在位機器上,指針變量的大小為個字節。指針類型的強制類型轉換對指針變量進行強制類型轉換的一般形式將保存的類型指針強制轉換為類型指針后賦值給,其中還是為,沒有改變。 前言 大家好,我是努力學習的少年,今天這篇文章是專門寫關于指針的知識點,因為指針內容比較多,所以我將指針的這篇文章我將它分為...
摘要:數據的存儲前言數據類型匯總整型家族浮點型家族自定義類型指針類型。整型家族注在之后的標準規定,將類型數據劃分為整型家族,因為字符在內存中會將其轉化為碼值進行存儲。 ...
摘要:寫在前面博客主頁的江湖背景的江湖背景歡迎關注點贊收藏留言本文由原創,首發首發時間年月日最新更新時間年月日堅持和努力一定能換來詩與遠方向未見花聞學習參考書籍深入理解計算機系統作者水平很有限,如果發現錯誤,請留言轟炸哦萬分感謝感謝感謝 ?寫在前面 ?博客主頁:kikoking的江湖背景?...
閱讀 4428·2021-09-09 09:33
閱讀 2385·2019-08-29 17:15
閱讀 2373·2019-08-29 16:21
閱讀 980·2019-08-29 15:06
閱讀 2619·2019-08-29 13:25
閱讀 581·2019-08-29 11:32
閱讀 3255·2019-08-26 11:55
閱讀 2594·2019-08-23 18:24