2014-12-03 30 views
1

我很困惑,通過使用工會,我嘗試了不同的方式來訪問它失敗。舉個例子:如何在C中訪問工會

union 
{ 
    struct 
    { 
     char cycle; 
     char freq; 
     char id; 
    } Umember_a; 

    char Umember_b[3]; 
} data_u; 

char info[3]; 

我要複製的「信息」陣列工會「data_u」,但我發現有錯誤,如果我使用下列的任何一個:

memcpy(data_u, info, sizeof(data_u)); 
memcpy(&data_u, info, sizeof(data_u)); 
memcpy(data_u.Umember_a, info, sizeof(data_u)); 
memcpy(data_u.Umember_a, info, sizeof(data_u.Umember_a)); 

,但我可以使用:

memcpy(data_u.Umember_b, info, sizeof(data_u.Umember_b)); 
memcpy(&data_u.Umember_a, info, sizeof(data_u.Umember_a); 

你能幫我解釋一下嗎?

+1

你得到了什麼錯誤,對於每一個這四個? – unwind 2014-12-03 10:27:19

+0

@Gopi以及'strcpy()'比'memcpy()'更好嗎[如果不是更糟]? – 2014-12-03 10:28:02

+0

@Gopi,我不會在這裏使用'strcpy',因爲它沒有定義'char'數組是零終止的。 'memcpy'或'strncpy'似乎更適合。 – 2014-12-03 10:28:28

回答

4

不幸的是,這種方法註定要失敗,因爲您認爲cycle,freqid在結構中緊密排列。這不一定是這種情況:編譯器可以自由地以任何方式對齊結構成員。

可以使用memcpy複製infoUmember_b。這是安全的,因爲(i)數組保證連續並且(ii)Umember_b[0]的地址將與data_u的地址相同。但你不知道memcpy將如何分佈在Umember_a的元素上。

某些編譯器允許您更改結構包裝,但這不足以實現可靠。

+1

爲什麼編譯器會填充不需要填充的成員?因爲它是免費的?請原諒我的無知,但是編譯器是否可以在他們實際需要它時自由調整成員? 「自由對齊」並不意味着爲了自由地去做而隨心所欲,隨意和不合邏輯的行爲。在這方面,「註定要失敗」根本不準確,更像是「不能保證按標準工作,但實際上99.99999999999999%的時間工作」。 – dtech 2014-12-03 10:48:46

+1

你也可以使用'offsetof'輕鬆檢查,如果對齊不符合邏輯的預期,就表示錯誤。你是否應該在深層地下掩體中度過你的生活,只是因爲隕石會隨時撞到你身上? – dtech 2014-12-03 10:51:18

+0

@ddriver:因爲將不支持8位讀取的體系結構中的每個字段與32位邊界對齊可能更高效?也就是說,sizeof(data_u)== 12'不是不合理的。 – MSalters 2014-12-03 11:32:12

0

顯然你不能做像memcpy(data_u, info, sizeof(data_u));這樣的事情,因爲memcpy需要一個指針,但是你傳遞了一個變量。這與工會無關。傳遞指向memcpy 的指針的情況下不應該給出錯誤。因爲在C中,任何指針都可以隱式地轉換爲/從void*。如果你在這裏得到一個錯誤,那是因爲你錯誤地將你的C代碼編譯爲C++,它具有更嚴格的類型要求。

memcpy(&data_u, info, sizeof(data_u));將工作,但嚴格來說這打破了C的別名規則。特別是因爲C結構/聯合可能包含填充字節。無論你打算如何處理這個工會,你都需要考慮填充。

memcpy(data_u.Umember_b, info, 3);是最安全和最正確的方法。是否實際工作取決於是否有填充。