bug表現:程式中有一個C++類,它的一個int型變數表現極其詭異,明明給它賦值,但是讀出的資料與賦給它的值不一樣。通過除錯,發現它在讀取記憶體時錯誤,偏移了3個位元組。在這個int型變數的前面,宣告了一個bool變數,除錯發現如果將bool變數放到int型變數之后,表現正常。后來發現,在程式中的其他地方(程式不是我寫的),定義了一些1位元組對齊的結構體,然后基本確認是位元組對齊問題。果然在該C++類定義前面加上#pragma pack()這行代碼,表現正常。然而,令人費解的是,我查看了所有代碼檔案,所有的#pragma pack(1)最終都接了一行#pragma pack(),將位元組對齊設為vs中默認的位元組對齊8.這里我有個疑問:既然設定了位元組對齊,程式應該就會按照我的設定進行對齊訪問,不應該會出現記憶體訪問錯誤,為什么還會出現上述bug。而且之前的結構體重#pragma pack(1)和#pragma pack()都是成對出現的,也不可能會影響到C++類啊。(注:程式用VS編輯編譯的)
關于代碼,其實很簡單:
//C++類
class Myclass{
public:
mystruct st;
bool is_connect;
int id;
}
//其他結構體定義檔案:
#pragma pack(1)
struct mystruct{
char a;
short int b;
}
#pragam pack()
uj5u.com熱心網友回復:
僅供參考:#include <stdio.h>
#define field_offset(s,f) (int)(&(((struct s *)(0))->f))
struct AD { int a; char b[13]; double c;};
#pragma pack(push)
#pragma pack(1)
struct A1 { int a; char b[13]; double c;};
#pragma pack(2)
struct A2 { int a; char b[13]; double c;};
#pragma pack(4)
struct A4 { int a; char b[13]; double c;};
#pragma pack(8)
struct A8 { int a; char b[13]; double c;};
#pragma pack(16)
struct A16 { int a; char b[13]; double c;};
#pragma pack(pop)
int main() {
printf("AD.a %d\n",field_offset(AD,a));
printf("AD.b %d\n",field_offset(AD,b));
printf("AD.c %d\n",field_offset(AD,c));
printf("AD sizeof %d\n", sizeof(AD));
printf("\n");
printf("A1.a %d\n",field_offset(A1,a));
printf("A1.b %d\n",field_offset(A1,b));
printf("A1.c %d\n",field_offset(A1,c));
printf("A1 sizeof %d\n", sizeof(A1));
printf("\n");
printf("A2.a %d\n",field_offset(A2,a));
printf("A2.b %d\n",field_offset(A2,b));
printf("A2.c %d\n",field_offset(A2,c));
printf("A2 sizeof %d\n", sizeof(A2));
printf("\n");
printf("A4.a %d\n",field_offset(A4,a));
printf("A4.b %d\n",field_offset(A4,b));
printf("A4.c %d\n",field_offset(A4,c));
printf("A4 sizeof %d\n", sizeof(A4));
printf("\n");
printf("A8.a %d\n",field_offset(A8,a));
printf("A8.b %d\n",field_offset(A8,b));
printf("A8.c %d\n",field_offset(A8,c));
printf("A8 sizeof %d\n", sizeof(A8));
printf("\n");
printf("A16.a %d\n",field_offset(A16,a));
printf("A16.b %d\n",field_offset(A16,b));
printf("A16.c %d\n",field_offset(A16,c));
printf("A16 sizeof %d\n", sizeof(A16));
printf("\n");
return 0;
}
//AD.a 0
//AD.b 4
//AD.c 24
//AD sizeof 32
//
//A1.a 0
//A1.b 4
//A1.c 17
//A1 sizeof 25
//
//A2.a 0
//A2.b 4
//A2.c 18
//A2 sizeof 26
//
//A4.a 0
//A4.b 4
//A4.c 20
//A4 sizeof 28
//
//A8.a 0
//A8.b 4
//A8.c 24
//A8 sizeof 32
//
//A16.a 0
//A16.b 4
//A16.c 24
//A16 sizeof 32
//
//
uj5u.com熱心網友回復:
在設計記憶體結構時,必須考慮對齊問題(一般4位元組)如果定義的char和bool 總數%4不為0,就需要放占位位元組。或者在存取時直接使用指標。uj5u.com熱心網友回復:
你這個應該是對mystruct這個結構 對齊不一致造成的 如果參考同一個h 都是一樣的對齊方式 應該是沒問題的 估計是你讀取用的是另一個默認對齊方式的mystructuj5u.com熱心網友回復:
用 push pop 限定作用范圍#pragma pack(push, 1)
struct mystruct{
char a;
short int b;
};
#pragma pack(pop)
uj5u.com熱心網友回復:
頂起來,也碰到類似問題。uj5u.com熱心網友回復:
我的想法和你差不多,應該是讀的方式是另一個對齊方式。但是沒找到出問題地方。我現在都是在出問題的類上方再加了一句#pragma pack(),雖然暫時解決了問題,但是不知道具體問題是出在哪?
uj5u.com熱心網友回復:
這個和我代碼中的方法應該也差不多吧,由于專案中有很多這樣的設定了,就沒改push,pop的這種方式了。
uj5u.com熱心網友回復:
最好是修改這個結構為4位元組對齊,雖然麻煩一些,但是值得。位元組對齊這東西是個麻煩的事情,所以一開始定義結構或者類時,就必需考慮這個問題,以減少后期因為位元組對齊而出現問題的可能性。
如果是協議類的東西不在自己的控制范圍內,則可以寫個類來實作對實際結構的決議和組裝,這樣后期的維護會容易得多。
使用
uj5u.com熱心網友回復:
建議用頭檔案,而不是 #pragma 因為不同編譯器支持的指令略有不同:#include <pshpack1.h>訪問偏移用 offsetof 宏不就行了。
typedef struct {
char a;
short int b;
} mystruct;
#include <poppack.h>
mystruct ms;
char *pc = (char *)((UINT_PTR)&ms + offsetof(mystruct, a));
short int *ps = (short int *)((UINT_PTR)&ms + offsetof(mystruct, b));
uj5u.com熱心網友回復:
我也碰到過,同一個工程,默認的對齊,不同版本經過一段演化,中間加入了對不同設備操作的不同廠商庫,有一個版本就不對了,經過一番查找原因,發現也是記憶體對齊不對了,手動把一些結構體弄的跟其他工程一樣,就正常了。也沒找到原因。
uj5u.com熱心網友回復:
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/123993.html
標籤:基礎類
上一篇:VC++ MFC 選單
