简体   繁体   中英

Complicated structure offsets in contiguous space

I would like to know if there is an elegant alternative to this:

struct A{
  uint64_t w;
  uint64_t x;
  uint64_t y;
  uint64_t z;
};

struct B{
  uint32_t a;
  uint16_t b;
};

void function(uint32_t length){
 //we have one struct A at the head and multiple struct B.
 struct B *ptr = malloc (length * sizeof B + sizeof A);

 //we set random values in the head:
 struct A * tmp = (struct A*)ptr;
 tmp->w = 1000;
 tmp->x = 1200;
 tmp->y = 99;
 tmp->z = ~(0ULL);

 /*then we set the first element of type B.
  *this is where my question lies
  */
 // put the pointer at the right position:
 tmp++;
 //convert that position again:
 struct B * right_position = (struct B*)tmp;

 ...// do things with B type.

}

Obviously, it would be simpler to have those fitted like so:

struct root{
struct A child1;
struct B *child2;
}

But my question is much more about the way to mark those offset down properly without writing the tmp++ .

How could I directly access the first B element on that array without using tmp++ ?

Again, this is not how I would do it in real code. This is just.. kind of art we are discussing here, if you will :)

Perhaps struct B * right_position = (struct B*)((char *)ptr + sizeof(A)); . The (char *) cast will make the calculation be performed in bytes.

struct A *a_ptr = malloc(sizeof(struct A) + length * sizeof(struct B));
struct B *b_ptr = (struct B *)(a_ptr + 1);

Maybe you should create a structure type with a flexible array member :

struct Both
{
    struct A a;
    struct B b[];
};

struct Both *c = malloc(sizeof(*c) + length * sizeof(c->b[0]));

c->a.w = 1000;
c->a.x = 1200;
c->a.y = 99;
c->a.z = ~(0ULL);

c->b[0].a = 37;
c->b[0].b = 59;

This guarantees alignment and doesn't require any casting or other chicanery. It's a part of C99 and C11 and replaces the struct hack . The standard (ISO/IEC 9899:2011) says:

§6.7.2.1 Structure and union specifiers

¶18 As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member . In most situations, the flexible array member is ignored. In particular, the size of the structure is as if the flexible array member were omitted except that it may have more trailing padding than the omission would imply. However, when a . (or -> ) operator has a left operand that is (a pointer to) a structure with a flexible array member and the right operand names that member, it behaves as if that member were replaced with the longest array (with the same element type) that would not make the structure larger than the object being accessed; the offset of the array shall remain that of the flexible array member, even if this would differ from that of the replacement array. If this array would have no elements, it behaves as if it had one element but the behavior is undefined if any attempt is made to access that element or to generate a pointer one past it.

The standard then has paragraphs 20-25 with examples discussing aspects of the use of flexible array members.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM