大端(big endian) 小端(little endian) --- 在多字節存儲 和 多字節通信中的含義(我還是太年輕了)

#PS:要轉載請註明出處,本人版權所有

#PS:這個只是 《 我自己 》理解,如果和你的

#原則相沖突,請諒解,勿噴

背景

出來工作了兩年有餘了,其中有很多次接觸到大小端的問題,每次都是拍一下腦袋,按照記憶中的內容做東西。(小端:高地址存高字節,低地址存低字節;大端:高地址存低字節,低地址存高字節)沒有做深入的理解,導致我最近遇到一個通信接口文檔,文檔標註的是大端模式,但是我按照自己的記憶中的大端去做,卻寫錯了,這不是我記憶有問題,只是我沒有理解到位而已。

Big endian And Little endian(大小端)

在多個字節讀寫或者傳輸過程中,哪個字節作爲高字節,哪個字節作爲低字節,需要我們人爲定義的。於是人們定義了大端模式和小端模式。但是我們常見的一句話:“小端:高地址存高字節,低地址存低字節;大端:高地址存低字節,低地址存高字節。”是指的多字節存儲中的定義。對於多字節傳輸中,大端小端這樣記憶或者說理解可能會出問題。

多字節存儲(我們常見的大小端定義)

多字節存儲中,就一句爛大街的話,小端:高地址存高字節,低地址存低字節;大端:高地址存低字節,低地址存高字節。很好理解。
用代碼測試也非常簡單,如下:(其實兩個方法原理都是指針)

#include <iostream>
#include <iomanip>
#include <cstdint>

union test_byte_order{

	uint16_t a;
	uint8_t b;
}test0;

int main(int argc, char * argv[]){

	test0.a = 0xAAFF;
	
	//byte-order-check based on union 
	//Notice that the basefield flag only affects the insertion/extraction of integer values (floating-point values are always interpreted in decimal base).
	std::cout<<"addr of test0.a is "<<std::hex << (uint64_t)&test0.a <<std::endl;
	std::string union_ret = (test0.b == 0xFF)?"little endian":"big endian";
	std::cout<<union_ret<<std::endl;


	//byte-order-check based on pointer 
	uint16_t a = 0xAAFF;
	uint8_t * b = (uint8_t *)&a;
	std::cout<<"addr of a is "<<std::hex << (uint64_t)&a <<std::endl;
	std::string pointer_ret = (*b == 0xFF)?"little endian":"big endian";
        std::cout<<pointer_ret<<std::endl;

	return 0;
}

gdb調試結果(符合預期)
在這裏插入圖片描述

常見的x86 是小端模式
現在常見的arm 支持大小端模式

多字節通信(人爲約定)

多字節通信的問題的話,其實就是你是先發送高字節,還是先發送低字節位的問題。其實如果通信文檔中一般都定義了先發送高還是低字節,但是如果通信文檔中換一種說法(大端模式、小端模式)的話,可能就需要思考一下,或者說需要理解一下才行。

例如tcp/ip協議中,對於ip地址和端口號,要求的必須是網絡字節序,也就是大端字節序模式。那我們到底是先發送高字節還是先發送低字節呢?其實在其他的232/485/can/藍牙/等等通信方式中,也有同樣的概念。

那對於多字節通信中,人爲定義了(注意,這裏的定義的概念和多字節存儲中的是同等級的,你可以理解爲他們兩個沒有關係):
大端序模式:先發送高字節,後發送低字節。
小端序模式:先發送低字節,後發送高字節。

既然上述概念是大多數人爲約定的,那麼可能就有這樣那樣的誤解。所以,一般通信文檔上說明了大端模式、還是小端模式外,還需要標註MSB or LSB first,或者直接註明先發高或者是低字節,避免雙方出現誤解。

當然,有沒有方法可以記憶多字節通信中,這種大多數人定義的概念呢?下文提供了一種我的記憶方案吧。

	//x86-64 ubuntu 18.04
	uint16_t ttt = 0xAABB;
	uint16_t ttt_hton = htons(ttt);//把ttt轉換爲網絡字節序,大端模式
	uint8_t array[4] = {0xAA, 0xBB, 0xCC, 0xDD};

在這裏插入圖片描述

在這裏插入圖片描述
在c&&c++數組中,數組名字是指向的這個數組的低地址。假如我要按地址自增方向發送這個數組的數據,如果數組中先存放高字節(也就是說低地址存放高字節,或者說先發送高字節),那麼這種通信方案中,字節序爲大端模式。小端模式同理可得。

但是,這僅僅是一種記憶方案。而且這是一種通用的約定,具體還是要看通信文檔的定義,例如tcp/ip中的ip和端口號字節序定義就是MSB first。如果某一天,哪個人可能直接定義大端模式就是先發送低字節,也是有可能的。

總結

大小端對於存儲和通信來說,我個人認爲有着不同的含義。雖然可以通過一些方法聯繫起來記憶。

但是我認爲,以上的內容都不是重點,是一些概念的東西,重點的是,你要明白爲啥會出現這個大小端的問題?什麼是字節序?爲什麼會有字節序這個概念就行了?

#PS:請尊重原創,不喜勿噴

#PS:要轉載請註明出處,本人版權所有.

有問題請留言,看到後我會第一時間回覆

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章