2011-03-21 157 views
3

我正在使用一個函數庫,它具有一個結構數組。這種結構和功能具有以下佈局:將一個int結構轉換爲一個int數組

struct TwoInt32s 
{ 
    int32_t a; 
    int32_t b; 
}; 

void write(struct TwoInt32s *buffer, int len); 

我最初的測試表明,這種結構的數組有相同的內存佈局的int32_t數組,所以我可以做這樣的事情:

int32_t *buffer = malloc(2 * len * sizeof(int32_t)); 
/* fill in the buffer */ 
write((struct TwoInt32s*)buffer, len); 

但是我想知道這是否是普遍正確的。使用數組int32_t可以大大簡化我的代碼。

編輯:我忘了的sizeof

從我讀,C可以保證約結構填充幾件事情:

  1. 成員將無法重新排序
  2. 填充只會成員之間加入不同的對齊或結構的末尾
  3. 指向結構的指針指向與其第一個成員相同的內存位置
  4. each membe r被以適當的方式對準,用於它的類型
  5. 可以有根據需要在結構無名孔來實現對準

從這我可以推斷出ab在它們之間沒有填充。但是結構可能會有填充。我對此表示懷疑,因爲它在32位和64位系統上都是字對齊的。有沒有人有關於此的更多信息?

+0

小心'len'是什麼意思。這是分配的內存量(可能不是)或數組中的結構數量!使用sizeof()和malloc:malloc(2 * sizeof(TwoInt32s)); – James 2011-03-21 17:29:47

+0

@詹姆斯 - 是的,我忘了sizeof。這是在我的實際代碼中。 – 2011-03-21 17:43:47

回答

10

該實現可以自由填充結構 - 在ab之間可能有未使用的字節。它保證了第一個成員不會從結構的開頭偏移。

您通常與特定編譯器編譯管理這樣的佈局,e.g:

#pragma pack(push) 
#pragma pack(1) 
struct TwoInt32s 
{ 
    int32_t a; 
    int32_t b; 
}; 
#pragma pack(pop) 
+0

我從中得出答案是「否」。不幸的是,我無法控制結構(它來自庫),所以我無法打包它。 – 2011-03-21 17:43:04

+1

@Niki Yoshiuchi:那麼你運氣不好,除非lib已經有這個包裝。如果你不需要可移植的*和*你的平臺有這個結構打包你想要的,那麼你可以投。在這種情況下,我會在佈局上設置static_assert(sizeof struct == 2 * sizeof int32_t)。 – Erik 2011-03-21 17:46:40

+0

從我讀過的內容來看,只有成員之間有不同的數據對齊時,纔會在成員之間添加填充。這意味着在我的情況下'a'和'b'應該始終是連續的。不過,填充也可以在最後添加。我不確定是否有任何保證。我猜想,因爲這個結構在32位系統上是字對齊的,所以我可以保證在32位系統上沒有填充。 – 2011-03-21 18:11:13

3

的malloc分配字節。你爲什麼選擇「2 * len」?

你可以簡單地使用「的sizeof」:

int32_t *buffer = malloc(len * sizeof(TwoInt32s)); 
/* fill in the buffer */ 
write((struct TwoInt32s*)buffer, len); 

和埃裏克提到,這將是包裝結構一個很好的做法。

+0

是的,我匆匆輸入並忘記了sizeof。 – 2011-03-21 17:40:55

2

最安全的是不進行轉換,而是進行轉換 - 即創建一個新數組並填充結構中找到的值,然後刪除該結構。

0

你可以分配結構,但其成員當作一種虛擬陣列:

struct TwoInt32s *buffer = malloc(len * sizeof *buffer); 

#define BUFFER(i) (*((i)%2 ? &buffer[(i)/2].b : &buffer[(i)/2].a)) 

/* fill in the buffer, e.g. */ 
for (int i = 0; i < len * 2; i++) 
    BUFFER(i) = i; 

不幸的是,GCC也不鐺目前「搞定」這個代碼。

+0

這是一種巧妙的技巧,但我特別需要與此相反。 – 2011-03-21 19:26:36