Reputation: 11453
I am a little confused about how bytes are ordered in a struct
.
Let's say I have the following struct:
struct container {
int myint;
short myshort;
long mylong;
};
Now, I want to initialize a variable of type struct container
just like the following, except that I want to do it using an array.
struct container container1 = {.myint = 0x12345678,
.myshort = 0xABCD,
.mylong = 0x12345678};
Assume sizeof
int
and long
are 4
, and that of short
is 2
.
Assume there is no padding.
How would then the layout of the 10 bytes
of the struct
be?
Does it depend on the endianness?
Would be it be like:
0x12345678 ABCD 12345678
or like:
0x78563412 CDAB 78563412
What I want to do is: I have the following char array:
char buffer[10] = {0};
I want to manually fill this array with data and then memcpy
to the struct
.
Should I be doing[1]:
buffer[0] = 0x12345678 & 0xFF;
buffer[1] = 0x12345678 >> 8 & 0xFF;
buffer[2] = 0x12345678 >> 16 & 0xFF;
buffer[3] = 0x12345678 >> 24 & 0xFF;
...
buffer[9] = 0x12345678 >> 24 & 0xFF;
or should it be[2]:
buffer[0] = 0x12345678 >> 24 & 0xFF;
buffer[1] = 0x12345678 >> 16 & 0xFF;
buffer[2] = 0x12345678 >> 8 & 0xFF;
buffer[3] = 0x12345678 & 0xFF;
...
buffer[9] = 0x12345678 & 0xFF;
before I do my memcpy
like:
memcpy(&container1, buffer, sizeof(container1);
And, if I am writing to an array and copying to struct
, Is it portable across systems, especially with regards to endianness?
EDIT: Does [1] work on a little endian machine and [2] on a big endian?
Upvotes: 7
Views: 3391
Reputation: 33601
There is another problem, that of element alignment within your struct.
Your struct has gaps for alignment. The real layout is as if you did:
struct container {
int myint;
short myshort;
char __pad__[2]; // padding to align mylong to 4/8 byte boundary
long mylong;
};
What about using a union
:
union {
struct container vals;
char buf[10];
};
But, why do you want to do this? For almost any scenario I can think of, there is probably a cleaner way to get the effect.
When you say array, do you mean you'd like to init an array of your structs? This can be done:
struct container conts[3] = {
{ .myint = 1, .myshort = 2, .mylong = 3 },
{ .myint = 4, .myshort = 5, .mylong = 6 },
{ .myint = 7, .myshort = 8, .mylong = 9 }
};
BTW, there is a way to do static_assert
in C:
// compile time assertion -- if the assertion fails, we will get two case 0:'s
// which will cause the compiler to flag this
#define static_assert(_assert) \
do { \
switch (0) { \
case (_assert): \
break;
case 0: \
break; \
} \
} while (0)
Upvotes: 1
Reputation: 4835
Does it depend on the endianness?
Yes it does depends on the endianness of the machine. So your logic will change depending on the endianness of the machine.
There is no portable way* to do it because of structure padding. Although different compilers do provide custom ways to disable struct padding. Check Force C++ struct to not be byte aligned.
You can add a static_assert
(requires C11 support) just to be sure that your code doesn't compiles unless your struct is tightly packed. You won't have portable code but you still can be sure that if your code compiles, it will behave correctly.
static_assert(sizeof(container) == sizeof(int) + sizeof(short) + sizeof(long));
Upvotes: 3