今天早上自己寫了一段代碼,然后測試的時候發現結果總是和預期的不一樣,而且偏差的有點離譜,冥思苦想了將近五個小時,最后在我要開始懷疑人生的時候,發現原來是自己犯了一個極其低級但又容易被忽略的問題。好吧,我承認我有點丟程序員的人了。
廢話不多說,直接開始用例子來說明吧:
我的代碼里有兩個結構體,假設為結構體Head和結構體Data,其結構如下:
struct Data{ int a; char b; short c; long d; }; struct Head{ int fieldcount; Data fielddata[1]; };
其中,結構體Head包含結構體Data的指針,且fieldcount表示后續有多少Data。我是將這個數據存儲在緩沖區中(假設緩沖區為char buf[1024])。當我通過如下代碼取數據的時候,發現取出來的數據結構體Data完全不是自己要的:
1 Head* h = (Head*) (buf+offset); 2 size_t datalen = sizeof (Head) + (h->fieldcount-1) * sizeof (Data); 3 offset += datalen; 4 5 for(size_t i=0;i<h->fieldcount;++i) 6 { 7 Data* data=(Data*)(h+sizeof(Head)+(i-1)*sizeof(Data)); 8 printf("a: %d b: %c \n", data->a,data->b); 9 }
不知道大家看出來問題沒有,我竟然研究這一段這么簡單的代碼研究了五個小時,簡直丟人啊。直接說問題吧。問題出在這句代碼:
1 Data* data=(Data*)(h+sizeof(Head)+(i-1)*sizeof(Data));
我的本意是想依次取出來Head后面的data的,即通過Data指針操作內存。可是我卻忘記了(指針+偏移量)的含義了。這里的偏移量看起來很正確,是以字節為單位的數,其實對於指針來說,是加了偏移量*sizeof(Head)的字節數,這里的偏移量,意思是加了多少個Head,這也是指針的奇妙之處,也是平時容易忽略的地方。所以每次我讀Data的時候,總是讀的很靠后面的內存,到時候讀的數據存在問題。修改后的代碼如下:
1 Data* data=(Data*)((char*)h+sizeof(Head)+(i-1)*sizeof(Data));
當然,我的環境是在linux上,以utf-8為編碼格式,所以char是一個字節,當然這里具體環境可以修改代碼。
溫馨提示:
在調試代碼的時候,還發現一個容易出錯的地方,就是注意字節對齊問題。當你把數據存到緩沖區時,如果數據是字節對齊,例如以1字節對齊的時候,如果取得時候沒有聲明對齊,那會存在意想不到的效果,哈哈聰明的你可以嘗試,反正我是嘗試過了。
