Reputation: 13
union a {
struct a_header a_hdr;
struct b b_hdr;
};
bzero((char*)(&(&a->a_hdr)[1]), sizeof(struct b) - sizeof(struct a_header));
What does this call do? Where does (char*)(&(&a->a_hdr)[1])
point to?
Upvotes: 1
Views: 121
Reputation: 224457
Working under the assumption that struct b
is larger than struct a_header
(otherwise sizeof(struct b) - sizeof(struct a_header)
would be zero or very large since size_t
cannot be negative), this statement clears any bytes in union a
that are used by b_hdr
but not a_hdr
.
Breaking down the expression:
&a->a_hdr
Given than a
is a pointer to union a
, this gets the address of the a_hdr
field
(&a->a_hdr)[1]
This treats the above address as an array and gets the element at offset 1. There is none, so this would be undefined behavior, but then we have:
&(&a->a_hdr)[1]
Since a[b]
is exactly equivalent to *(a + b)
, the above is the same as:
&(*(&a->a_hdr + 1))
The &
and *
adjacent to each other cancel each other out, so now you have:
&a->a_hdr + 1
So this points one element past the array of length 1 that is a->a_hdr
. It is this address that is passed to bzero
. The cast to char *
is unnecessary since bzero
takes a void *
as its first parameter.
The second parameter:
sizeof(struct b) - sizeof(struct a_header)
Again, assuming struct b
is bigger than struct a_header
, this gives us the number of bytes that struct b
is bigger by. So the bytes used by b_hdr
but not a_hdr
are cleared.
To illustrate, suppose the struct b
is 8 bytes and struct a_header
is 4 bytes. Then a union a
would look like this:
---------------------------------
| X | X | X | X | X | X | X | X |
---------------------------------
| struct b |
---------------------------------
|struct a_header|
-----------------
Where X
is some unknown byte value. After the above call to bzero
, it looks like this:
---------------------------------
| X | X | X | X | 0 | 0 | 0 | 0 |
---------------------------------
| struct b |
---------------------------------
|struct a_header|
-----------------
Upvotes: 1
Reputation: 1100
I'm going to take a guess and say that struct b has a definition like,
struct b {
struct a_header header;
... [other stuff]
}
The union allows you to access the member elements of the header more easily.
The line you have gets the address of the start of the [other stuff] portion of the struct b, and sets it to zero.
Breaking it down, starting from the inside
&a->a_hdr
a is a pointer to the union of type union a (kinda confusing). This line gets the memory at the a_hdr portion of the union, this changes the type to struct a_header, then we get the address of it. The address here doesn't actually change, rather it is a safe way of casting the pointer to be of type struct a_header.
&(&a->a_hdr)[1]
we treat the pointer to struct a_header as an array and get memory of the next element, then get the address of that memory. Essentially we have done a + sizeof(struct a_header)
. This only makes sense if you know what is in the memory after struct a_header, either because you have an array or a struct like I placed in the above section.
(char*)(&(&a->a_hdr)[1])
the cast changes the pointer type, it probably isn't necessary as most bzero implementations take a void pointer, but it doesn't hurt either.
bzero((char*)(&(&a->a_hdr)[1]), sizeof(struct b) - sizeof(struct a_header))
bzero is a function which sets a chunk of memory to zero, an alternative to memset. The second parameter sets the size, the subtraction strongly suggests that struct b contains as it's first member a variable of type struct a_header. The pointer manipulations in the first parameter skip over that element, the second parameter sets the size to be the remainder of struct b, bzero then clears this portion.
Upvotes: 0