2011-03-21 116 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