Size of a struct with union and bitfields - c

I'm trying to count the size in bytes of this struct and have a couple of questions
struct stc {
int a;
int b;
char c;
union stc2 {
long a0;
int a1;
int a2;
};
char arr[10];
int z:2;
};
I'm checking the size in this way:
int main(void) {
printf("%zu\n", sizeof(struct stc));
}
and compile with:
gcc -std=c99 -m32 -Wall -Wextra test.c
It's gcc 4.9 and I'm on 64-bit computer but first want to try with 32-bit values so -m32. Now, the result is 20, but I've no idea why is that. This is how I'm counting.
struct stc {
int a; // +4 = 4
int b; // +4 = 8
char c; // +1 but next is long, so +4 (alignment) = 12
union stc2 {
long a0; // +4 = 16
int a1;
int a2;
};
char arr[10]; // +8 (for arr[8]) and 2 bits left = 24 (or 28)
int z:2; // +4 = 28 (or 32)
// I'm not sure how it'll work with 2 bits left from char array and
// 2 bits from int, so that why I count 2 different values.
};
This was strange so I tried to figure this out and I know that this union seem to be size 0.
struct stc {
union stc2 {
long a0;
int a1;
int a2;
};
sizeof(struct stc) == 0. I think that is because of compiler optimization? If so, how to turn it off? If not, why is that?
Another question is of course how to count the size of this struct properly (with or without optimization) and why the size of this simple struct:
struct stc {
char arr[10];
};
is 10 not a 12. I've thought that every value is aligned to 4,8,12,16,20 etc if you won't say to compiler to not align values.

So you have a lot of questions in here. I'll answer some as I go:
sizeof struct is zero?
You gave the code:
struct stc {
union stc2 {
long a0;
int a1;
int a2;
};
};
Note that you declared no variables inside the struct. You probably meant to do the following, which will likely have the same size as sizeof(long).
struct stc {
union stc2 {
long a0;
int a1;
int a2;
} x;
};
Bitfield layouts
So, let's try to figure out where 20 comes from. First, let's rerwite the type without the union that isn't doing anything (see previous heading).
Also, note that structs with bitfields are not required to be laid out in memory the same way as normal types. But let's make some guesses anyways.
struct stc {
int a; // Offset 0, Size 4
int b; // Offset 4, Size 4
char c; // Offset 8, Size 1
char arr[10]; // Offset 9, Size 10
int z:2; // Offset 19, Size 1-ish
};
So it seems to fit fine.
sizeof wasn't rounded up to 12?
struct stc {
char arr[10];
};
So, each type has a size and an alignment requirement. For char, both of these are 1. For uint32_t, they are usually both 4. But depending on the architecture, the alignment could be different.
So in this case, the maximum alignment needs of any element of the struct stc is 1. So the alignment requirements of the entire struct is still 1, even though the size is 10.
Generally speaking, you want to add whatever padding is necessary to the size such that the declaration struct stc x[2] would cause all of the elements to be properly aligned.
Recommendations
So, there are a few things that you could do here to help learn what your compiler is doing.
When posting questions about memory layout on stack overflow, it's very helpful to use the types defined in stdint.h. These include types like int32_t and int16_t. These are nicer because there is no confusion on what size a long is.
You can use the offsetof tool to determine where a compiler is placing the members. You can learn some more about how to use it here.
Padding can occur though:
Here's a pretty simple example of a struct with a good bit of padding that the compiler would have to insert.
struct x {
uint64_t x; // Offset 0, Size 8
char y; // Offset 8, Size 1
// Offset 9, Size 1 (Padding)
uint16_t z; // Offset 10, Size 2
// Offset 12, Size 4 (Padding)
};

Related

padding struct with different types of fields

I already referred to this question, but still can't find an answer for this following case.
Why does the padding not apply for the case of test1?
#include <stdio.h>
typedef unsigned short u16;
typedef unsigned char u8;
typedef struct
{
u8 a[5];
u8 b;
u8 c;
} test1;
typedef struct
{
u8 a[5];
u16 b;
} test2;
int main(void) {
test1 t1;
test2 t2;
printf("t1 = %d\n", sizeof(t1));
printf("t2 = %d\n", sizeof(t2));
return 0;
}
Output:
t1 = 7
t2 = 8
Update
After the answers from #ryyker and #Ajay Brahmakshatriya, i made another test code and it seems the answers don't apply to this case... If the padding size is 3, because the size of type test1 is 3, why does the size of test2 not 9 instead of 7?
#include <stdio.h>
typedef unsigned short u16;
typedef unsigned char u8;
typedef struct
{
u8 a;
u8 b;
u8 c;
} test1;
typedef struct
{
test1 a[2];
u8 b;
} test2;
int main(void) {
test1 t1;
test2 t2;
printf("t1 = %d\n", sizeof(t1));
printf("t2 = %d\n", sizeof(t2));
return 0;
}
Output:
t1 = 3
t2 = 7
The alignment requirement of a struct is greater than equal to the alignment requirement of each its member. Also, the alignment requirement of an array is the same as that of its elements.
If the alignment requirement of u8 is 1 byte and the alignment requirement of u16 is 2 bytes, the alignment requirement of test1 would be at least 1 byte and that of test2 would be at least 2 bytes.
Since the alignment requirement of test2 is 2 bytes, its size should also be a multiple of 2 bytes (this way if you declare an array of the struct, all the elements of the array can be aligned properly).
The sum of sizes of elements of test2 is 7 bytes. The closest multiple of 2 is 8 bytes.
For test1, since the alignment requirement is only 1 byte, 7 is an acceptable size.
Finally, the implementations are allowed to add any amount of padding to the structs as long it satisfies all the above constraints. So there is no right way to answer the question "Why is the size of this struct not equal to what I calculated?". What I have here is a likely rationale as to why your implementation chose the current sizes.
Why does the padding not apply for the case of test1... Because bytes are the smallest natural memory segment, and in the case of the first struct the only type used, the compiler sets memory alignment for this struct at one byte segments. None of the members bump up against that natural alignment. Therefore padding is not required.
In the second struct definition there is one u16 type, and an odd number of bytes (5) stored in the array member. The u16 member causes alignment boundaries ( | ) to be (by default) two bytes:
The first struct could be viewed as a series of byte memory locations, with 1 byte alignment:
|.......|.......|.......|.......|.......|.......|.......| ( 7-bytes )
a[0] a[1] a[2] a[3] a[4] b c
The second struct, with the u16 member, uses 2-byte alignment: (thus also results in padding.)
|...............|...............|...............|..............| (8-bytes )
a[0] a[1] a[2] a[3] a[4] (padding) b
Note, default alignment boundaries can be modified by using a pragma statement. For example pragma pack(1) forces the alignment boundary to 1 byte. This would effectively place b adjacent to a[4] in memory, and would make the second struct the same size as the first.
|.......|.......|.......|.......|.......|.......|.......| ( 7-bytes )
a[0] a[1] a[2] a[3] a[4] b
pragma pack(1)//force alignment to 1 byte
typedef struct
{
u8 a[5];
u16 b;
} test2;
pragma pack()// set packing back to what it was
Even though this question/answer talks about pragma statements, it covers the surrounding concepts, such as the one you are asking about well.

How to fix allocation size of a struct

I have a struct
typedef struct
{
int A ;
int B ;
…
} SomeStruct ;
I have an instance of SomeStruct that I want to persist to Flash memory which has a sector size of 512 bytes. What GCC attribute can I apply to that instance such that the allocation size is a multiple of 512 bytes?
The only options I can think of are :-
1) Pad the struct to make it exactly 512 bytes. This requires recalculation every time a field is added to the struct. No compiler warnings when I get it wrong. Also struct is larger than needed with normal initialisation, copying etc.
2) Place the variable in a separate Linker section. This provides full protection and warnings, but gets a bit tedious if multiple variables are used.
3) Make a union of the struct and a 512 byte array. Copes with adding extra fields until the struct is greater than 512 bytes, then fails without any warnings.
Referring 1:
#include <assert.h>
#define FLASH_BYTES (512)
#pragma pack(1)
struct flash
{
struct data
{
int i;
char c;
...
};
char pads[FLASH_BYTES - sizeof (struct data)];
};
#pragma pack()
int main(void)
{
assert(sizeof (struct flash) == FLASH_BYTES);
...
The assert might even not be necessary because if the result
FLASH_BYTES - sizeof (struct data)
is negative any GCC should issue an error. To make sure it will be negative cast the result of the sizeof operation to any signed integer, like for example so:
FLASH_BYTES - (int) sizeof (struct data)
So trying to compile this
#pragma pack(1)
struct flash
{
struct data
{
int i;
char c[FLASH_BYTES];
};
char pads[FLASH_BYTES - (int) (sizeof (struct data))];
};
#pragma pack()
int main(void)
{
}
You should be giving you something like:
main.c:14:12: error: size of array ‘pads’ is negative
char pads[FLASH_BYTES - (int) sizeof (struct data)];
A portable solution is to define a union of SomeStruct, with a char array whose size is calculated to meet the necessary alignment.
typedef struct
{
int A;
int B;
char c[512];
} SomeStruct;
#define STORAGE_ALIGNMENT 512
typedef union
{
SomeStruct data;
char paddedData[((sizeof(SomeStruct) + STORAGE_ALIGNMENT - 1) / STORAGE_ALIGNMENT) * STORAGE_ALIGNMENT];
} SomeStructAligned;
Online running version (Coliru) here
The sizing formula is well known and works for any integer. Since this is a power-of-2 you could also simplify it down to the form (sizeof(SomeStruct) + (STORAGE_ALIGNMENT - 1)) & ~(STORAGE_ALIGNMENT - 1)) == (sizeof(SomeStruct) + 0x1ff) & ~0x1ff). In practice you may need ~size_t(0x1ff) on the rightmost term to ensure portability to 64-bit machines; since 0x1ff is an int (32-bit), ~0x1ff results in a 64-bit 0x00000000fffffe00 value instead of the desired 0xFFFFFFFFfffffe00 mask.
Sub-Optimal Approach
An alternative approach could have been to define a wrapper struct containing your original data plus some automatically calculated padding.
typedef struct
{
int A;
int B;
} SomeStruct;
#define STORAGE_ALIGNMENT 512
typedef struct
{
SomeStruct data;
char padding[(STORAGE_ALIGNMENT) - (sizeof(SomeStruct) % STORAGE_ALIGNMENT)];
} SomeStructAligned;
Online running version (Coliru) here.
However, the above is not perfect: if sizeof(SomeStruct) is a multiple of 512, then sizeof(padding) will be 512, wasting a quantum of storage. Whereas the union never wastes space.
You can try something like this (though it is a dirty bit trick)
#define ROUND_UP_512(x) ((x) + 511 & ~511)
struct myStruct {
// put whatever
};
union myUnion{
myStruct s;
char ensureSize[ROUND_UP_512(sizeof(myStruct))];
};
in this case the size of "myUnion" is guaranteed to be a multiple of 512 that is greater than or equal to the size of "myStruct"

Memory alignment in C-structs under Windows 32bits

Here is a snippet:
struct a {
float* f;
char c;
int i;
char z[4];
double d;
short s;
};
struct b {
struct a a1;
int j;
struct a a2;
};
When I do a printf("%d\n",sizeof(struct a)), it emits to me 32... But when I do the same for the struct b, it emits 72 which I don't know how can be possible this, it should be 32+4+28(padding)+32 following the same calcs that I did to find out the previous result... can anyone tell me why is this happening?
From my calculations, struct a requires 26 bytes (including padding in the middle) + 6 bytes at the end. It looks something like this:
struct a {
float* f; // takes 4 bytes
char c; // takes 1 bytes + 3 padding
int I; // takes 4 bytes
char z[4]; // takes 4 bytes
double d; // takes 8 bytes, sets a requirement for memory alignment
short s; // takes 2 bytes.
// here there are 6 more bytes for padding required for array alignment.
};
The double in the struct means that struct a must be positioned on an 8 byte alignment mark, so that the double is correctly aligned.
Now, when we have struct b, we have:
struct b {
struct a a1; // takes 32 bytes, REQUIRES and 8 byte alignment
int j; // takes 4 bytes + 4 byte padding (for alignment).
struct a a2; // takes 32 bytes, MUST start on an 8 byte alignment
};
I hope this wasn't homework or something... :-p
Nothing is aligned to more than multiples of 8 for the x86/amd64 architectures. See for example Structure Alignment for Visual Studio. struct a and struct b have a double member, so they must be aligned at a multiple of 8 and their sizeof must be a multiple of 8; you can easily see why 32 is correct for struct a. The int j is 4 bytes, at a multiple of 4; since it comes immediately after struct a a1 it need no padding, being placed a multiple of 8. struct a a2 needs to be at a multiple of 8, so 4 bytes of padding are added. Overall, struct b needs 32 bytes for member a1, 4 bytes for member j, 4 bytes of padding (to bring a2 to a multiple of 8) and 32 for member a2 for a total of 72.

Generate padding bytes for a structure by nesting it in a union

I was going through this question to reaffirm my understanding of structure padding.I have a doubt now. When I do something like this:
#include <stdio.h>
#define ALIGNTHIS 16 //16,Not necessarily
union myunion
{
struct mystruct
{
char a;
int b;
} myst;
char DS4Alignment[ALIGNTHIS];
};
//Main Routine
int main(void)
{
union myunion WannaPad;
printf("Union's size: %d\n\
Struct's size: %d\n", sizeof(WannaPad),
sizeof(WannaPad.myst));
return 0;
}
Output:
Union's size: 16
Struct's size: 8
should I not expect the struct to have been padded by 8 bytes? If I explicitly pad eight bytes to the structure, the whole purpose of nesting it inside an union like this is nullified.
I feel that declaring a union containing a struct and a character array the size of the struct ought to be but isn't, makes way for a neater code.
Is there a work-around for making it work as I would like it?
Think about it logically.
Imagine I had a union with some basic types in it:
union my_union{
int i;
long l;
double d;
float f;
};
would you expect sizeof(int) == sizeof(double)?
The inner types will always be their size, but the union will always be large enough to hold any of its inner types.
should I not expect the struct to have been padded by 8 bytes?
No, as the struct mystruct is seen/handled on its own. The char had been padded by 3 sizeof (int) -1 bytes to let the int be properly aligned. This does not change, even if someone, somewhere, sometimes decides to use this very struct mystruct inside another type.
By default struct is padded, so int b field is aligned on sizeof(int) boundary. There are several workarounds for this:
explicitly use fillers where needed: char a; char _a[sizeof(int)-1]; int b;
use compiler-dependent pragma to pack struct on byte boundary
use command-line switch etc.

How to add an array to a bitfield struct?

I tried to use bit fields in a struct for some values which only need one or two bits instead of a whole byte.
My code is:
struct s_rdata {
signed int p0:28;
signed int p1:28;
signed int p2:28;
unsigned int d0:17;
unsigned int d1:17;
unsigned int d2:17;
unsigned char data1:1;
unsigned char data2:1;
} rdata;
So, you might see that there are variables named p0 - p2, d0 - d2 and data1 - data2.
I'd now like to have those in an array. However, none of this lines does work:
signed int p[3]:28;
signed int p:28[3];
Can't I add an array to a bitfield list, an array of signed int only needing 28 bits per entry?
No, you cannot have an array of bitfields, nor a bitfield whose base type is an array type. The latter doesn't even make sense. The former would be counter-productive, as you would lose any space efficiency gained by using bitfields in the first place.
You can have an array of a structs with a single bitfield member:
struct container {
signed int bitfield:7;
} array[3];
but again, you would lose any space efficiency associated with the bitfield use.
You can create an array of any struct type, of course, including those with multiple bitfield members. In that case, you may achieve some internal space efficiency within the individual structures, but you will likely see padding at the end of each one that reduces the overall space efficiency of the array.
Ultimately, unless your program's memory consumption is excessive for its target environment, I strongly recommend that you forget about bitfields. They will complicate your life for an uncertain gain of uncertain importance, and that gain will likely be offset by a performance degradation (of uncertain magnitude and importance).
Should you eventually decide that the program really is using too much memory, then be certain to test any change you make to see how much improvement it yields, and at what cost.
I agree with #John's assessment with respect to space inefficiencies, but that notwithstanding, here is an idea to contain contents of a bit field within struct array:
typedef struct
{
int A : 16;
int B : 16;
} Struct1;
typedef struct
{
Struct1 B;//bitfield struct
int array[10];//combined with array (of any legal type)
}
Here is an example of populating array with contents of bit struct:
typedef struct {
signed int p0:28;
signed int p1:28;
signed int p2:28;
unsigned int d0:17;
unsigned int d1:17;
unsigned int d2:17;
unsigned char data1:1;
unsigned char data2:1;
} RDATA;
typedef struct {
int A[3];
unsigned int B[3];
unsigned char C[2];
} ARRAY;
RDATA rdata = {//initialize instance of RDATA with data
28,
28,
28,
17,
17,
17,
1,
1
};
int WriteToArray(ARRAY *a);
int main(void)
{
ARRAY a;
WriteToArray(&a);//populate array with RDATA values
//ARRAY is now populated with bitfield values;
a.A[0];
a.A[1];
//and so on
return 0;
}
WriteToArray(ARRAY *a)
{
a->A[0]=rdata.p0;//using values initialized above
a->A[1]=rdata.p1;
a->A[2]=rdata.p2;
a->B[0]=rdata.d0;
a->B[1]=rdata.d1;
a->B[2]=rdata.d2;
a->C[0]=rdata.data1;
a->C[1]=rdata.data2;
return 0;
}
You can also experiment with pragma pack statements to look at effects on space, but refer to #John's comment under your post for additional considerations regarding pragma and spacing.

Resources