在網絡傳輸中,很多數據都是按字節傳遞而不是字符串。最近就遇到了這個問題,在剛開始學c語言時都沒有問題,可能太久不用了,記錄一下
在報中文,用2個字節hex碼來表示報文正文長度,什么是hex碼呢 就是16進制數
char c = ‘\b’;
那么c的整數類型就是8(ascii 8對應\b)
char類型是可以直接轉int的 我犯得錯誤就是用atoi來轉整形,aoti轉的是字符串類型到整形 比如"123"轉為123,而如果"b"用atoi 則轉出來的為0
而如果網絡報文中用兩個字節來表示長度的話,可以用
char *c=....
*(short*)(c);
四字節用
*(int*((c);
單個字節就直接找到長度的那位字符 如*(int*)(c[10])
2019/5/29
在解析報文長度的字節時,直接把報文中代表長度的兩個字節拷到 數組中 char c[2];c[1]為'0',c[2]為8'\b',在這里我直接用*((short*)(c)) 來把字節轉為數字。期望的結果是8,卻得出了2048.。。
這里就要從大小端開始說。數組 c在內存中的分布是 00 08,而inter x86 是小端機,short類型為兩個字節,讀出來的字節序就為0800了,這就是原因。 需要轉換一下字節序即可。
下面是幾個轉換的方法
對於字數據(16位):
#define BigtoLittle16(A) (( ((uint16)(A) & 0xff00) >> 8) | \
(( (uint16)(A) & 0x00ff) << 8))
對於雙字數據(32位):
#define BigtoLittle32(A) ((( (uint32)(A) & 0xff000000) >> 24) | \
(( (uint32)(A) & 0x00ff0000) >> 8) | \
(( (uint32)(A) & 0x0000ff00) << 8) | \
(( (uint32)(A) & 0x000000ff) << 24))
延伸出來的問題是,為什么數組沒有大小端這一說法呢? 猜測應該是數組內存經過管理不用大小端轉換
2019/6/12 更新 浮點數也沒有大小端之分,其內存結構應該遵循IEEE制定的規范。
下面為一篇浮點數在內存中分布的講解
http://www.ruanyifeng.com/blog/2010/06/ieee_floating-point_representation.html
2019/6/13更新 今天又被現實上了一課。。。
發現報文中傳輸的數據,是這樣子的
這是wireshark抓的包,里面是hex即16進制字符,對方給的數據在16進制下顯示為19060310,而實際的十進制下也是19060310。。。這種寫法真是挺少見的
處理的方法只能一個字節一個字節處理了,先處理每個字節的高4位,保存一下,再處理低四位(每個16進制的高低四位分開看其實就等於它的十進制數據,說不太明白。。。) 查了一下 就是 hex轉string
char str_hex[] = "\x19"; char pp = str_hex[0] >> 4; char pppp = str_hex[0] & 0x0F; char endppp = pp * 10 + pppp;
思考了一下 發現這種寫法可以節約空間提升傳輸效率,如果12這個數字通過轉換成字符串的類型發送,則要耗費2個字節,而如果轉換為16進制字節的表示形式,只需要一個字節即可。缺點就是轉換繁瑣,容易出錯
#include <iostream> #include <stream> #include <sstream>
//deep為s長度減1
//2019/6/27更新 修改將無符號字節解析為有符號數從而出現負數的情況
static int hex2d(string s, int deep)
{
if (s.empty())
return 0;
//每次只解析一個字節
unsigned char high4 = (s[0] >> 4) &0x0F;
unsigned char low4 = s[0] & 0x0F;
unsigned char ch_ret = high4 * 10 + low4;
int n = 0;
n = pow(100, deep);
return ch_ret*n + hex2d(s.substr(1), deep - 1);
}
使用方法 hex2d(str,str.size()-1)
另一種方法
https://blog.csdn.net/sunflover454/article/details/51219472