有時我對結構進行指標運算,我不確定它是否是定義的行為。
如果我有這個結構
typedef struct SCustomData{
uint32_t a;
uint32_t b;
}CustomData;
有時對我來說,不必不斷地輸入結構的不同欄位,而是給它一個恒定的大小并適合我需要的任何內容。
我的第一個問題是:結構的地址也是結構中第一個變數的地址是否定義了行為?
int main(){
CustomData cd = {0};
cd.a = 0xDEADBEEF;
uint32_t a = 0;
memcpy(&a,&cd,sizeof(uint32_t));
assert(a==0xDEADBEEF);
return 0;
}
這會永遠成功嗎?
我的下一個問題是,只要我知道每個成員的大小,我可以使用指標演算法來訪問結構的任何成員嗎?
int main(){
CustomData cd = {0};
cd.b = 0xABCD0000;
uint16_t highshort = *(uint16_t*)((uint8_t*)&cd sizeof(uint32_t) sizeof(uint16_t));
assert(highshort == 0xABCD);
uint8_t highbyte = *(uint8_t*)((uint8_t*)&cd sizeof(uint32_t) sizeof(uint16_t) sizeof(uint8_t));
assert(highbyte == 0xAB);
return 0;
}
除了可能看起來丑陋或糟糕的代碼實踐之外,至少是定義的行為嗎?我應該避免嗎?
如果我不使用指標轉換而是使用 memcpy ,這仍然是一個壞主意嗎?
int main(){
CustomData cd = {0};
cd.b = 0xABCD0000;
uint16_t highshort = 0;
memcpy(&highshort, ((uint8_t*)&cd) sizeof(uint32_t) sizeof(uint16_t), sizeof(uint16_t));
assert(highshort == 0xABCD);
return 0;
}
uj5u.com熱心網友回復:
第一個問題
它實際上是在 C 標準中定義的!部分6.7.2.1(在本標準草案中)
15 在結構物件中,非位域成員和位域所在的單元的地址按宣告順序遞增。一個指向結構物件的指標,經過適當的轉換,指向它的初始成員(或者如果該成員是位域,則指向它所在的單元),反之亦然。結構物件中可能有未命名的填充,但不是在其開頭。
第二個問題
它不是根據標準定義的(再次部分6.7.2.1):
結構或聯合物件的每個非位域成員都以適合其型別的實作定義的方式對齊。
但是,大多數編譯器以相同的方式對齊(至少按架構和位數)
為什么這仍然是個壞主意
可維護性 - 如果您自己使用成員,您的代碼將更容易維護。它不會依賴于編譯器和位數,并且不會對代碼中的更改(例如更改型別或重新排序成員)敏感。
可讀性——你的意圖當然會更清晰。
有時編譯器會做一些奇怪的事情;)
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/477682.html
標籤:C
上一篇:在C中當前行程的堆中搜索和編輯值
下一篇:宣告與定義:GCC錯了嗎?
