0

This is my program

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main() {
    struct bitfield {
         unsigned a:3;
         char b;
         unsigned c:5;
         int d;
    }bit;

    printf("%lu \n",sizeof(bit));
    return 0;
}

I was expecting size of this structure to be, well quite a lot, but it comes out to be 8 on my machine, because unsigned is 4 bytes. Now reason I was expecting to be more than that was because I would expect char b to be on a byte boundary, so that it is aligned in the memory correctly. Now my guess is that compiler is putting a, b, c, all in those 4 bytes. I am new to C, so please bear with me. Is my assumption that all the other data types besides bit fields have to be necessarily on byte incorrect? If it is correct, I would expect, a to take the whole unsigned int, and b to take a byte and then padding of 3 bytes, and then so on. What am I missing here?

  • Perhaps this answers your question: [How is the size of a struct with Bit Fields determined/measured?](https://stackoverflow.com/questions/4129961/how-is-the-size-of-a-struct-with-bit-fields-determined-measured) – Luboš Hemala Jul 30 '17 at 19:45
  • No it doesnt. I know how bit field sizes are measured. My question is, if I have a char in between, how are they then measured – user3491702 Jul 30 '17 at 19:46
  • Simply put, stay as far away from bitfields as you can. There is not a single reason in the world to use them. Having said that, why would you expect `a` to occupy the same space as an entire unsigned int? It is a bit field, it occupies 3 bits, regardless of what comes before or after it. – n. m. could be an AI Jul 30 '17 at 19:47
  • Do a test how big a struct of 4 char fields is. Or a single char. I think it's 1 byte. So they would fit in your order (3+8+5 < 32) – Luboš Hemala Jul 30 '17 at 19:47
  • @n.m. Ideally, I wouldnt expect a to occupy same space as entire unsigned int. My question is, how will they be arranged in memory, if we have a bitfield a, and then char b. Where does char b go? Does it go in those leftover bits from a? If not, then how do you justify the size of struct that i am getting – user3491702 Jul 30 '17 at 19:49
  • @LubosHemala So you are saying that char b goes into the leftover bits from a? – user3491702 Jul 30 '17 at 19:50
  • "Ideally, I wouldnt expect a to occupy same space as entire unsigned int". Your expectation is not founded in either experiment or standards documents, so just drop it and accept the fact. `a` occupies 3 bits. That's what `:3` in its definition says. `b` has no influence on it whatsoever. It goes to the next byte that has no bits occupied by `a`. – n. m. could be an AI Jul 30 '17 at 19:55
  • @n.m. You need to relax and bear with people who have confusion regarding understanding of a data type. If not, this platform is not for you. – user3491702 Jul 30 '17 at 19:56
  • @user3491702 Have you read all the answers in my previous link? Anyway, have a look at [Data structure alignment](https://en.wikipedia.org/wiki/Data_structure_alignment) perhaps it will make things clearer. I am not sure that byte alignment is always enforced, when you use bit fields. Compiler uses by default 32 or 64 bit fields based on your architecture in which it tries to pack as much as possible. – Luboš Hemala Jul 30 '17 at 19:58
  • 1
    `sizeof` is no way related to the alignment by the standard. A byte is the minimal unit of measure for both (`1`). An object cannot be not aligned to a byte. – too honest for this site Jul 30 '17 at 20:02

2 Answers2

3

I don't seem to understand the conflict.

you basically have:

struct bitfield {
     unsigned a:3;
     unsigned padding1:5;
     char b;
     unsigned c:5;
     unsigned padding2:3;
     unsigned padding3:8;
     int d;
}bit;

a is on byte 1 boundary, it uses three bits + 5 bit padding (because there aren't any more bit fields to use up the leftover bits).

b is on byte 2 boundary, it uses a whole byte.

c is on byte 3 boundary, it uses five bits + 3 bit padding (because there aren't any more bit fields to use up the leftover bits).

- int padding comes here -

d is on an int boundary (4 bytes on your machine). It uses 1 byte for padding + 4 bytes for data.

All together, 8 bytes...

... although, as pointed out by @ JonathanLeffler in the comments, this is implementation specific and doesn't mean every compiler will behave the same.

Myst
  • 18,516
  • 2
  • 45
  • 67
  • Thanks Myst. Just the explanation i was looking for. Sorry I am new to the language so I am still learning the basics of the data types – user3491702 Jul 30 '17 at 19:57
  • 2
    The confusion probably arises because the compiler is permitted, but not required, to use the type (`unsigned` in this example) for the storage of the bit-field defined to be of that type, and therefore to use 4 bytes for the first bit-field, 1 byte for the `char`, 3 bytes padding to align the next bit-field on a 4-byte boundary, 4 bytes for the second bit-field, and 4 bytes for the `int`, for a total of 16 bytes. This is all implementation-specific, like almost everything to do with bit-fields. – Jonathan Leffler Jul 30 '17 at 20:00
  • @JonathanLeffler When I read the question, thats what my calculations told me, that it should be 16 bytes. I guess more I read into bit fields and unions, and endianess, more I realize how implementation-specific they are. – user3491702 Jul 30 '17 at 20:03
  • @user3491702: If you need a specific layout, a `struct` is not the type of choice. A bitfield `struct` just adds additional variations. Use an array of `uint8_t` or another fixed-width type for such data and bitops/shifts for marshalling. – too honest for this site Jul 30 '17 at 20:09
  • @Olaf thank you for the suggestion. I will definitely look into it. Here, I was not trying to get a specific layout, but was trying to understand it. – user3491702 Jul 30 '17 at 20:11
  • Thanks @JonathanLeffler , I added a comment about this is in the answer. – Myst Jul 30 '17 at 20:38
2

You usually align the bitfields in that way they share a single byte together. When you place another variable in between bitfields, the unused bits end up using space in memory you don't need but still use space.

I tested your code with some values and ran the program in gdb.

bit.a = 1;
bit.b = 'a';
bit.c = 4;
bit.d = 1337;

When printing the memory in gdb, the output looks like this

(gdb) x/8b &bit
0x7fffffffe118: 00000001    01100001    00000100    00000000
                00111001    00000101    00000000    00000000

So we see that the first byte is completely used from field a, although it only uses 3 bits. The character a in field b also takes up a byte. The third byte (00000100) matches value 4 of field c and here's whats interesting:

You then have an integer which uses 4 bytes (in the gdb output above the last 4 bytes, bottom line), but there's an extra zero byte in there. This is a common pratice for compilers as they try to align the memory in an optimized way.

CRoemheld
  • 889
  • 7
  • 26