c語言強制記憶體轉化引發的問題

9606發表於2020-11-11

問題描述

在最近計算機網路的實驗中,構造IP資料包時使用了C語言的強制記憶體轉化,最終的程式出現了一個bug:

char* sendBuffer = (char*)malloc(37 * sizeof(char));
((uint16_t*)sendBuffer)[1] = 37; //0x25
sendBuffersendBuffer + 1sendBuffer + 2sendBuffer + 3

程式本身期望使用((uint16_t*)sendBuffer)[1]sendBuffer + 2sendBuffer + 3的兩個連續位元組作為一個整體訪問,使其中的內容被改寫為0x0025,但實際上被改寫為了0x2500

問題分析

在經過實驗後發現,即使進行了了強制型別轉換,將char*轉為了uint16_t*,使用((uint16_t*)sendBuffer)[1]也不能將sendBuffer + 2sendBuffer + 3並不能作為作為一個整體訪問,依然會按照sendBuffer宣告時的char*型別將sendBuffer + 2sendBuffer + 3作為兩個位元組進行處理。
37被解釋為0x0025,由於小端機的緣故,數字邏輯低位0x25儲存在記憶體的物理低位sendBuffer + 2,數字的邏輯高位0x00儲存在記憶體的物理高位sendBuffer + 3,造成了最終結果為0x2500,而不是期望的0x0025

驗證

為了驗證上述想法,測試如下程式碼

unsigned short ch[20];
((unsigned int*)ch)[0] = 0x12345678;

unsigned short佔2位元組,unsigned int佔4位元組

按照上面的分析,(unsigned int*)ch[0]不能將前4個位元組作為一個整體訪問,而是會按照陣列ch宣告中的unsigned short,將前4個位元組分為兩個2位元組處理。
執行結果如下:
在這裡插入圖片描述
前4個位元組被改寫為了0x 5678 1234,而不是0x 1234 5678。結合上面所述的小端機的原因,可知道這4個位元組確實是分成了兩個2位元組處理,而不是作為一個4位元組整體。我們的分析是正確的。

相關文章