开发者

Cast a struct of ints to an array of ints

开发者 https://www.devze.com 2023-02-18 00:25 出处:网络
I am using a library that has a function that takes an array of structs.That struct and function has the following layout:

I am using a library that has a function that takes an array of structs. That struct and function has the following layout:

struct TwoInt32s
{
  int32_t a;
  int32_t b;
};

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

My initial tests suggest that an array of such structs has the same memory layout as an array of int32_t so I can do something like this:

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

However I'm wondering if this i开发者_如何学Cs universally true or not. Using an array of int32_t greatly simplifies my code.

EDIT: I forgot the sizeof

From what I read, C guarantees a few things about struct padding:

  1. members will NOT be reordered
  2. padding will only be added between members with different alignments or at the end of the struct
  3. a pointer to a struct points to the same memory location as a pointer to its first member
  4. each member is aligned in a manner appropriate for its type
  5. there may be unnamed holes in the struct as necessary to achieve alignment

From this I can extrapolate that a and b have no padding between them. However it's possible that the struct will have padding at the end. I doubt this since it's word-aligned on both 32 and 64 bit systems. Does anyone have additional information on this?


The implementation is free to pad structs - there may be unused bytes in between a and b. It is guaranteed that the first member isn't offset from the beginning of the struct though.

Typically you manage such layout with a compiler-specific pragma, e.g:

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


malloc allocates bytes. Why did you choose "2*len" ?

You could simply use "sizeof":

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

and as Erik mentioned, it would be a good practice to pack the struct.


It's safest to not cast, but convert -- i.e., create a new array and fill it with the values found in the struct, then kill the struct.


You could allocate structures but treat their members as a sort of virtual array:

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;

Unfortunately, neither GCC nor Clang currently "get" this code.

0

精彩评论

暂无评论...
验证码 换一张
取 消