① c++ socket 發送位元組序結構體
數據傳輸時,如兩端無法採用統一的處理模塊,比如編寫語言不同(當然C++和C#其實可以使用相同的序列化/反序列化模塊,比如做成DLL)。最少需考慮兩點: 1.位元組對齊。C++/C#編譯環境通常可選,如不一致收發的數據長度將不一樣。 2.位元組順序,俗稱的大小端。系統內位元組順序為低位在前,高位在後,但網路發送時往往是高位在前,低位在後。 你可以發送時(C++端)按1Byte對齊,先發送結構體長度,再發送結構的整個內存數據塊,接收時(C#)按ByteStream方式接收,先接收長度,再根據長度接收數據塊,然後自解析數據。
② 大小端存儲
在計算機系統中,存儲是以位元組為單位的,每個地址單元都對應著一個位元組,一個位元組=8bit。在C語言中除了8bit的char之外,還有16bit的short型,32bit的long型(要看具體的編譯器)。對於位數大於8位的處理器,例如16位或者32位的處理器,由於寄存器寬度大於一個位元組,如何安排多個位元組的存儲,這就有了大端存儲模式和小端存儲模式。
小端:較高的有效位元組存放在較高的的存儲器地址,較低的有效位元組存放在較低的存儲器地址。
大端:較高的有效位元組存放在較低的存儲器地址,較低的有效位元組存放在較高的存儲器地址。
如果將一個16位的整數0x1234存放到一個短整型變數(short)中。這個短整型變數在內存中的存儲在大小端模式由下表所示。
C語言判斷大小端模式
方法一:
voidIsBigEndian()
{
shortinta=0x1122; //十六進制,一個數值佔4位charb = *(char*)&a;//通過將short(2位元組)強制類型轉換成char單位元組,b指向a的起始位元組(低位元組)
if( b ==0x11) //低位元組存的是數據的高位元組數據
{
//是大端模式
}
else
{
//是小端模式
}
}
方法二:
voidIsBigEndian() //原理:聯合體union的存放順序是所有成員都從低地址開始存放,而且所有成員共享存儲空間
{
uniontemp
{
shortint a;
char b;
}temp;
temp.a=0x1234;
if(temp.b==0x12) //低位元組存的是數據的高位元組數據
{
//是大端模式
}
else
{
//是小端模式
}
}
參考:https://www.jianshu.com/p/152268b0ea19
③ 大端模式和小端模式
具體如下:
1、大端模式:
大端模式,是指數據的高位,保存在內存的低地址中,而數據的低位,保存在內存的高地址中,這樣的存儲模式類似於把數據當作字元串順序處理。
地址由小向大增加,而數據從高位往低位放;小端模式,是指數據的高位保存在內存的高地址中,而數據的低位保存在內存的低地址中,這種存儲模式將地址的高低和數據位權有效地結合起來,高地址部分權值高,低地址部分權值低,和我們的邏輯方法一致。
在大端模式下,前16位應該這樣讀: e6 84 6c 4e ( 假設int佔4個位元組)。
記憶方法: 地址的增長順序與值的增長順序相反。
2、小端模式例子:
0000430: e684 6c4e 0100 1800 53ef 0100 0100 0000。
0000440: b484 6c4e 004e ed00 0000 0000 0100 0000。
在小端模式下,前16位應該這樣讀: 4e 6c 84 e6( 假設int佔4個位元組)。
記憶方法: 地址的增長順序與值的增長順序相同。
大小端模式:
為什麼會有大小端模式之分呢?這是因為在計算機系統中,我們是以位元組為單位的,每個地址單元都對應著一個位元組,一個位元組為 8bit。但是在C語言中除了8bit的char之外,還有16bit的short型,32bit的long型(要看具體的編譯器),另外,對於位數大於 8位的處理器。
例如16位或者32位的處理器,由於寄存器寬度大於一個位元組,那麼必然存在著一個如何將多個位元組安排的問題。因此就導致了大端存儲模式和小端存儲模式。例如一個16bit的short型x,在內存中的地址為0x0010,x的值為0x1122,那麼0x11為高位元組,0x22為低位元組。
對於 大端模式,就將0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,剛好相反。我們常用的X86結構是小端模式,而KEIL C51則為大端模式。很多的ARM,DSP都為小端模式。有些ARM處理器還可以由硬體來選擇是大端模式還是小端模式。
④ 大小端 int nTest=0x1234.若nTest在內存中起始地址為0x40000000,
對於32位int類型,int nTest=0x1234,也就是0x00001234
大端模式各個地址下的內容分別是:
0x40000000 0x00
0x40000001 0x00
0x40000002 0x12
0x40000003 0x34
小端模式各個地址下的內容分別是:
0x40000000 0x34
0x40000001 0x12
0x40000002 0x00
0x40000003 0x00
⑤ 編譯器能指定大小端么
大端模式,是指數據的高位元組保存在內存的低地址中,而數據的低位元組保存在內存的高地址中
小端模式,是指數據的高位元組保存在內存的高地址中
而數據的低位元組保存在內存的低地址中
上面c是一個共用體,給共用體中的a賦值為1.然後讀取b是否為1,當b為1是說明是小端模式,b為0則說明是大端模式。
⑥ 一個結構體變數在內存中是如何存儲的
結構體的變數的地址存儲在棧中,然後在堆中開辟控制項存儲真實的數據。
⑦ 為什麼會有大小端模式之分呢
這是因為在計算機系統中,我們是以位元組為單位的,每個地址單元都對應著一個位元組,一個位元組為8bit。但是在C語言中除了8bit的char之外,還有16bit的short型,32bit的long型(要看具體的編譯器),另外,對於位數大於8位的處理器,例如16位或者32位的處理器,由於寄存器寬度大於一個位元組,那麼必然存在著一個 如何將多個位元組安排 的問題。因此就導致了 大端存儲模式 和 小端存儲模式 。
例如一個16bit的short型x,在內存中的地址為0x0010,x的值為0x1122,那麼0x11為高位元組,0x22為低位元組。對於大端模式,就將0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,剛好相反。我們常用的X86結構是小端模式,而KEIL C51則為大端模式。很多的ARM,DSP都為小端模式。有些ARM處理器還可以由硬體來選擇是大端模式還是小端模式。
• Little-Endian:低位位元組排放在內存的低地址端,高位位元組排放在內存的高地址端。示例數字0x12 34 56 78在內存中的表示形式:
內存 低地址 -----------------> 高地址
0x78 | 0x56 | 0x34 | 0x12 *
低位子節 -----------------> 高位子節*
• Big-Endian:高位位元組排放在內存的低地址端,低位位元組排放在內存的高地址端。示例數字0x12 34 56 78在內存中的表示形式:
內存 低地址 -----------------> 高地址
0x12 | 0x34 | 0x56 | 0x78
高位子節 -----------------> 低位子節
可見,大端模式和字元串的存儲模式類似。但是也有各自的特點:
• 小端模式 :強制轉換數據不需要調整位元組內容,1、2、4位元組的存儲方式一樣。
• 大端模式 :符號位的判定固定為第一個位元組,容易判斷正負。
則可以通過以下方式判斷機器的子節序
或者 利用聯合體union成員的存放順序都是從低地址開始的特性來做判斷。
為了方便討論,假設m_RegMW[0] = 0x3456; 在內存中為0x56、0x34。
現要將該數據發出,如果不進行數據轉換直接發送,此時發送的數據為0x56,0x34。而Modbus是大端的,會將該數據解釋為0x5634而非原數據0x3456,此時就會發生災難性的錯誤。所以,在此之前,需要將小端數據轉換成大端的,即進行高位元組和低位元組的交換,此時可以調用步驟五中的函數BigtoLittle16(m_RegMW[0]),之後再進行發送才可以得到正確的數據。
⑧ 大小端模式的簡介
所謂的大端模式(Big-endian),是指數據的高位元組,保存在內存的低地址中,而數據的低位元組,保存在內存的高地址中,這樣的存儲模式有點兒類似於把數據當作字元串順序處理:地址由小向大增加,而數據從高位往低位放;
例子:
0000430: e684 6c4e 0100 1800 53ef 0100 0100 0000
0000440: b484 6c4e 004e ed00 0000 0000 0100 0000
在大端模式下,前32位應該這樣讀: e6 84 6c 4e ( 假設int佔4個位元組)
記憶方法: 地址的增長順序與值的增長順序相同 所謂的小端模式(Little-endian),是指數據的高位元組保存在內存的高地址中,而數據的低位元組保存在內存的低地址中,這種存儲模式將地址的高低和數據位權有效地結合起來,高地址部分權值高,低地址部分權值低,和我們的邏輯方法一致。
例子:
0000430: e684 6c4e 0100 1800 53ef 0100 0100 0000
0000440: b484 6c4e 004e ed00 0000 0000 0100 0000
在小端模式下,前32位應該這樣讀: 4e 6c 84 e6( 假設int佔4個位元組)
記憶方法: 地址的增長順序與值的增長順序相反 對於0x11223344 儲存如下
下面這段代碼可以用來測試一下你的編譯器是大端模式還是小端模式:
short int x;
char x0,x1;
x=0x1122;
x0=((char*)&x)[0]; //低地址單元
x1=((char*)&x)[1]; //高地址單元
若x0=0x11,則是大端; 若x0=0x22,則是小端......
上面的程序還可以看出,數據定址時,用的是低位位元組的地址。 #definesw16(x)((short)((((short)(x)&(short)0x00ffU)<<8)|(((short)(x)&(short)0xff00U)>>8)))
⑨ C語言讀寫二進制文件讀取 大小端,該怎麼解
先看下面的代碼,然後我在簡短的解釋一下。
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <string>#define nmemb 7/****************************************************fopen和fclose是很常見的,在這里就不做解釋了。我們來看看fwrite和fread,本來以為這個很麻煩,但是用過之後發現這個二進制文件讀寫才是最簡單的。
size_t fwrite(const void * ptr,size_t size,size_t nmemb,FILE * stream);
fwrite()用來將數據寫入文件流中。
stream為已打開的文件指針
ptr 指向欲寫入的數據地址
寫入的字元數以參數size*nmemb來決定。
size表示寫入一個nmemb的內存大小。
fwrite()會返回實際寫入的nmemb數目。
size_t fread(void * ptr,size_t size,size_t nmemb,FILE * stream);
fread()用來從文件流中讀取數據。
stream為已打開的文件指針
ptr 指向欲存放讀取進來的數據空間
讀取的字元數以參數size*nmemb來決定
size表示讀取一個nmemb的內存大小。
fread()會返回實際讀取到的nmemb數目,如果此值比參數nmemb 小,則代表可能讀到了文件尾或有錯誤發生,這時必須用feof()或ferror()來決定發生什麼情況。
返回實際讀取到的nmemb數目。
詳情參見上面的代碼。
另外就是大小端的問題了。關於大小端的具體解釋網上有很多,在此不作解釋。參考上面寫的代碼,我判斷了自己機器是大端還是小端,並且實現了int16,int32已經float數據類型的大小端轉換,大端轉小端,在使用相同的代碼一次小端又變成了大端。
PS:float的大小端轉化我之前一直以為寫的是錯的,因為好多數據轉化之後輸出都是0。後來發現可能是與float類型在內存中的存放有關,我們的程序是對的。
⑩ Big Endian 和 Little Endian的區別
區別是:
Big Endian可以在最小的地址里存儲一系列符號中最重要符號記憶的計算機,根據遞減的重要性存儲的方法。
Little Endian用最小的地址儲存最少的重要位元組 (而用最大的地址儲存最多的重要位元組)
的計算機記憶力。
在ARM體系中,每個字單元包含4個位元組單元或者兩個半字單元。在字單元中,4個位元組哪一個是高位位元組,哪一個是低位位元組則有兩種不同的格式:big-endian和little-endian格式。在小端模式中,低位位元組放在低地址,高位位元組放在高地址;在大端模式中,低位位元組放在高地址,高位位元組放在低地址。
如果將一個32位的整數0x12345678(如用UltraEdit打開某個文件看到的第一行頭四個位元組是:"00000000h:12 34 56 78")存放到一個整型變數(int)中,這個整型變數(文件內容)採用大端或者小端模式在內存中的存儲。
對於文件內容 0x12345678,把前面("12")的看為高端位元組,後面("78")的看為低端位元組,那麼可以使用"高高低低"(Little Endian),"高低高低"(Big Endian)的口訣。直觀的區分,如果發現內存的內容和文件的內容在順序上以4個位元組顛倒,那麼他就是Little Edian。實現Big Endian和Little Endian主要是由編譯器指定的,通常是在CCFLAG 加參數,如: -DENDIAN_LITTLE,設定編譯為小端位元組。實際中用Trace 32可以用Memory Dump查看內存內容,和寫入文件比較後判斷為大端還是小端。
如果將一個16位的整數0x1234存放到一個短整型變數(short)中。這個短整型變數在內存中的存儲在大小端模式。
採用大小模式對數據進行存放的主要區別在於在存放的位元組順序,大端方式將高位存放在低地址,小端方式將低位存放在低地址。
那麼該如何判斷CPU是大端模式還是小端模式呢?
在C語言中,聯合體union的存放順序是所有成員都從低地址開始存放的。利用這一特點,可以用聯合體變數判斷ARM或x86環境下,存儲系統是是大端還是小端模式。
具體的代碼如下:
#include "stdio.h"
int main()
{
union w
{
int a; //4 bytes
char b; //1 byte
} c;
c.a=1;
if (c.b==1)
printf("It is Little_endian!/n");
else
printf("It is Big_endian!/n");
return 1;
}