2015-04-05 70 views
-1

我有關於結構的C.行爲的問題您可以使用指向包含結構的指針來修改嵌套結構的值嗎?

以給定的結構爲例:

typedef struct { 
    char num1; 
    char num2; 
} structa; 

typedef struct { 
    structa innerstruct; 
    char num3; 
    char num4; 
} structb; 

我假設,因爲structb包含structa場,而不是指向一個,那structb將被佈置在內存中:

struct { 
    char num1; //innerstruct num1 
    char num2; //innerstruct num2 
    char num3; //num3 
    char num4; //num4 
}; 

如果是這樣,你能訪問每個字段嗎?

*(((char *)&structbvar) + 0) = 1; //innerstruct num1 
*(((char *)&structbvar) + 1) = 2; //innerstruct num2 
*(((char *)&structbvar) + 2) = 3; //num3 
*(((char *)&structbvar) + 3) = 4; //num4 

還是像這樣訪問它們?

((structa)structbvar).num1 = 1; //innerstruct num1 
((structa)structbvar).num2 = 2; //innerstruct num2 

無論這是否是不好的做法或不。

也是可靠/便攜嗎?


編輯,由馬特·麥克納布指出,你不能直接澆鑄結構,所以應該是:

((structa *)&structbvar)->num1 = 1; //innerstruct num1 
((structa *)&structbvar)->num2 = 2; //innerstruct num2 
+3

你可以試試它,你通常會擺脫它,但沒有定義它必須工作。不要這樣做;它會讓你的代碼超出理由而變得模糊。 – 2015-04-05 04:28:25

+0

我已經厭倦了我的系統,它似乎工作。事情是,但我不確定它是否便攜,如果不是,爲什麼不。我並不擔心這是否是不好的做法,但我已經知道它確實是這樣,我不會編寫這樣的代碼,但知道C如何蜱是很好的。 – LivePastTheEnd 2015-04-05 04:28:46

+1

你必須確保你的結構是對齊的 – 2015-04-05 04:57:57

回答

2

*(char *)版本是明確的,雖然你將需要經過檢查填充innerstruct的末尾以及num3之前。

(structa)structbvar不合格。我認爲*(structa *)&structbvar可以,因爲關於具有共同初始序列的結構的規則(儘管我會仔細檢查並更新我的答案)。然而,這是有點毫無意義,因爲你可以寫structbvar.innerstruct

+0

啊你對(structa)structbvar正確,我完全忘了你不能直接施放另一個結構,謝謝!我會在下面的編輯註釋中查找違規行。感謝關於填充的注意事項。我沒有想到這一點。 是的,我知道這有點無意義,但這更像是一個關於c剔除其他問題的問題。 – LivePastTheEnd 2015-04-05 04:40:27

2

如果您使用指針強制訪問struct字段,則代碼的可靠性取決於您的內存對齊方式。所以不建議這樣做,除非您按照預期強制內存對齊。

在不調用嵌套結構名稱的情況下訪問該字段的另一種方法是使用帶聯合的匿名結構。這是C99標準,當然是便攜和可靠的,除了你的編譯器不支持C99。

您可以定義一個聯盟與匿名Strct這樣的:

typedef union { 
    uint32_t wWord; 
    struct { 
     uint16_t hwLow; 
     uint16_t hwHigh; 
    }; 
} test_t; 

然後訪問每個字段是這樣的:

test_t tTest; 
tTest.wWord = 0x00FF0000; 

另外:

tTest.hwHigh = 0x00FF;