Re: [問題] C用結構指標操作資料的問題

作者: amoumou (amoumou)   2018-12-14 15:39:26
※ 引述《amoumou (amoumou)》之銘言:
: 開發平台(Platform):
: 我是在32Bit Renesas MCU上實作
: 我想要用結構指標來操作資料例如:
: // MSB bit7 - bit0 LSB
: // 要用來操作的結構
: typedef struct
: {
: uint8_t JoystickUpStatus:1;
: uint8_t JoyStickLeftStatus:1;
: uint8_t JoyStickRightStatus:1;
: uint8_t JoyStickDownStatus:1;
: uint8_t Pending1:4;
: uint16_t TimeCounter1:12;
: uint8_t Pending2:4
: uint16_t SpeedValue:16;
: uint8_t XStatus:2;
: uint8_t YStatus:2;
: uint8_t Pending3:2;
: uint16_t TimeCounter2:10;
: uint8_t Pending4:8;
: }MY_DAT_STRUCT; //8 bytes, 64bit total
: uint64_t TX_DATA = 0xF0CCF03FFE000008; //通常資料一次送8 bytes出去
: MY_DAT_STRUCT *my_dat_struct = (MY_DAT_STRUCT *)&TX_DATA;
: //以下為預期結果
: my_dat_struct->JoystickDownStatus 數值為 1;
: my_dat_struct->SpeedValue 數值為 0x3FFE;
: my_dat_struct->TimeCounter2 數值為 0xCCC;
: 實際跑出來結果跟預期相符。
: 這樣做的目的是希望增加程式的可讀性,能明確的知道哪些bit是做甚麼用的;
: 在讀取的時候也能快速的取出要的數值。
: 我想問的問題是(我的lib中沒有sizeof()可以用):
: 1. 若我宣告 MY_DAT_STRUCT my_dat; my_dat的size會是連續的64bits嗎?
: 2. 承上,若宣告為 *my_dat; 那麼size應該會是多少?
: 3. TX_DATA透過轉型成結構指標操作的話,會不會有潛在的問題(例如沒對齊)?
: 4. 這樣的作法(轉型操作)是正確/常見的使用方式嗎?
我做了一些測試跟爬文找到一些解答了。
首先上篇文章寫到的實際跑出來的結果跟預期相符是錯誤的,實際上位置偏移了。
原本我預期MY_DAT_STRUCT的Size應該是8 Bytes, 但實際上卻是10 Bytes,這與對齊的設定有關。
實際讀取變成
JoyStickRightStatus = 0
JoyStickLeftStatus = 0
JoyStickRightStatus = 0
JoyStickDownStatus = 1
Pending1 = 0
TimeCounter1 = 0xE00
Pending2 = 0xf
SpeedValue = 0xF03F
XStatus = 0
YStatus = 0x3
Pending3 = 0
TimeCounter2 = 0x3C3
Pending4 = 0x5C
會造成這樣的結果主要是沒有設定對齊或是資料的排列沒有最佳化,這個例子裡因為沒設定對齊方式,
預設會是自然對齊,也就是他會用結構內最大的uint16_t, 2bytes來對齊。
若我使用#pragma pack(1) 讓他用 1Byte來對齊就會是我預期的 8 Bytes大小了。
要設定對齊我所知的有兩種方式
1. 設定complier
2. 用#pragma pack(n)
關於我的第3個問題,我認為只要資料與結構的size及範圍相符,用結構指標操作應該是沒問題的。
第1及第4個問題我就不確定了;才疏學淺,以上若有錯誤的地方還拜託大家指正了,Thanks!
作者: kokal (細菌)   2018-12-16 22:46:00
1.從stack中分配sizeof(MY_DAT_STRUCT) 3.big/little EndiaEndian, 4.如果真的確定一樣的話, 我會用union
作者: amoumou (amoumou)   2018-12-17 21:21:00
非常感謝!Endian真是要注意的重點;我也會改用Union,比較能確定使用的是同一個空間。

Links booklink

Contact Us: admin [ a t ] ucptt.com