2017-02-10 121 views
1

比方說,我有一個結構類型:初始化與其他結構的內容之一結構

typedef struct 
{ 
    int a; 
    int b[3]; 
    int c; 
} __attribute__((packed)) foo_t; 

我初始化正是如此:

foo_t first = { 1, { 2, 3, 4 }, 5 }; 

現在我想創建第二個結構,是一個集第一個:

typedef struct 
{ 
    int b[3]; 
    int c; 
} __attribute__((packed)) bar_t; 

bar_t second = { first.b[3], first.c }; //this should define first.c as 5 
memcpy(second.b, first.b, 3 * sizeof(int)); 

如果我打印每個變量的值在second,th Ë陣列b正確定義,但c只是0

printf("%d %d %d %d\n", second.b[0], second.b[1], second.b[2], second.c); 

輸出

2 3 4 0 

爲什麼不second.c得到正確填充?

回答

0

在發帖之後幾秒鐘內回答了我自己的問題。

爲了用數組初始化新結構的內容,必須在數組部分的周圍放置大括號。此外,指定first.b[3]作爲初始化值實際上將獲取3元素數組的第4個元素,該元素是未定義的且代碼不正確。在下一行使用memcpy之前,{0}可用作任意大小數組的佔位符。所以,正確的代碼段應該是這樣的:

typedef struct 
{ 
    int b[3]; 
    int c; 
}__attribute__((packed)) bar_t; 

bar_t second = { {0}, first.c}; //this should define first.c as 5 
memcpy(second.b,first.b,3*sizeof(int)); 
+0

..這仍然留下'first.b [3]'是什麼值作爲'b'只有三個元素,你複製第四個元素。請注意,初始化程序是一個值,而不是定義。 –

+0

呵呵,好點。我明白你在說什麼。在這種情況下,我可以用「first.b [3]」來代替,直到我在下一行上執行memcpy爲止,作爲「佔位符」。請注意,在我正在處理的實際代碼中,數組很大,因此顯式鍵入'{first.b [0],first.b [1],first.b [2],first.b [3], first.b [4] .... etc}'是站不住腳的。 –

+1

我相信在一個初始化器中,所有沒有具體提到的元素都被設置爲零,所以'{{0},first.c}'應該做到這一點。請測試它。 –

0

對於代碼維護,使用memcpy()的結構複製到另外一個不同類型的,是有問題的:會發生什麼,如果一個(而不是兩者)涉及的結構類型是否被修改?

因此,我建議使用

typedef struct 
{ 
    int b[3]; 
    int c; 
} __attribute__ ((__packed__)) bar; 

typedef struct 
{ 
    int a; 
    bar bar; 
} __attribute__ ((__packed__)) foo; 

然後,將具有

foo first = {1, {2, 3, 4}, 5}; 
bar second; 

可以很明顯的做

second = foo.bar; 

就個人而言,我建議將訪問宏太, :

#define BAR_B(var, index) ((var).b[index]) 
#define BAR_C(var)  ((var).c) 

#define FOO_A(var)  ((var).a) 
#define FOO_B(var, index) ((var).bar.b[index]) 
#define FOO_C(var)  ((var).bar.c) 

它可以用作左值和右值(即,在任務的任何一方)。它使維護更容易,以防您需要稍後重新拆分或重新排列結構內容;那麼您不需要更改代碼本身,只需修改訪問器宏。

0

在您的定義中,first.c被解析爲second.b的第二個條目的初始化程序,該條目立即被memcpy覆蓋。順便提一句,first.b[3]是一個超出first.b末尾的無效訪問。通過初始化明確second.b元素

bar_t second = { { 0 } , first.c}; 
memcpy(second.b, first.b, sizeof(second.b)); 

您也可以擺脫memcpy的:

bar_t second = { { first.b[0], first.b[1], first.b[2] }, first.c}; 

爲了second.c用的first.c值進行初始化,初始化應該被改寫成

另請注意,__attribute__((packed))是不可移植的,並且在聲明中無用,因爲所有類型都是相同的。除非絕對必要,否則避免這種事情。