views:

152

answers:

2

Sizeof() doesn't work when applied to bitfields:

# cat p.c
  #include<stdio.h>
  int main( int argc, char **argv )
  {
    struct { unsigned int bitfield : 3; } s;
    fprintf( stdout, "size=%d\n", sizeof(s.bitfield) );
  }
# gcc p.c -o p
  p.c: In function ‘main’:
  p.c:5: error: ‘sizeof’ applied to a bit-field

...obviously, since it can't return a floating point partial size or something. However, it brought up an interesting question. Is there an equivalent, in C, that will tell you the number of bits in a variable/type? Ideally, it would also work for regular types as well, like char and int, in addition to bitfields.

Update:

If there's no language equivalent of sizeof() for bitfields, what is the most efficient way of calculating it - at runtime! Imagine you have loops that depend on this, and you don't want them to break if you change the size of the bitfield - and no fair cheating and making the bitfield size and the loop length a macro. ;-)

+2  A: 

You cannot determine the size of bit-fields in C. You can, however, find out the size in bits of other types by using the value of CHAR_BIT, found in limits.h. The size in bits is simply CHAR_BIT * sizeof (type).

Do not assume that a C byte is an octet, it is at least 8 bit. There are actual machines with 16 or even 32 bit bytes.

Concerning your edit: I would say a bit-field int a: n; has a size of n bits by definition. The extra padding bits when put in a struct belong to the struct and not to the bit-field.

My advice: Don't use bit-fields but use (arrays of) unsigned char and work with bitmasks. That way a lot of behaviour (overflow, no padding) is well defined.

schot
+1 cool, didn't know about CHAR_BIT. what if you needed to calculate the bitfield size at runtime?
eruciform
That is just not possible (one of the reasons why people avoid bit-fields). A compiler could implement this as an extension for this, but I have never heard of one.
schot
@schot: byte != char. In C, char is always 8 bit, thus `CHAR_BIT` is always 8. Regardless of CPU/etc. Long time ago it might have been different (constant exists for the historical reasons) but not anymore. Check C99, `limits.h`.
Dummy00001
@schot: what i meant by run-time is this. imagine you have a bitfield that's 3 bits long. you write a bunch of loops that hardcode 3 in them. then one day you change the bitfield to 4 and the loops break. other than putting that "3" in a location very close to the bitfield definition (would be a good idea anyways), what would be the best way to introspect? maybe shift a 1 til it turns to a 0? who knows... i'm curious the best method.
eruciform
@Dummy00001: Sorry, but you are wrong. The C99 standard gives a **lower limit** for CHAR_BIT as 8. And in Appendix J 3.4 It explicitly states as **implementation defined** behaviour *"The number of bits in a byte."*
schot
@schot: I think we're arguing wording. Section 3.6 (referred by J.3.4) clearly separates byte and char. char would always have 8 bits (as per limits.h' CHAR_BIT definition). if implementation's byte is larger, it has to truncate. Or as per 3.7.1 character is a `single-byte character` with `bit representation that fits in a byte`. Implementation's byte can be larger, but one will not be able to access the extra bits from C with `char`.
Dummy00001
@Dummy00001: I agree that a machine byte != C byte. But a char is not always 8 bits. 5.2.4.2.1: `"Their implementation-defined values shall be equal *or greater* in magnitude (absolute value) to those shown, with the same sign."` And then shows: `"- number of bits for smallest object that is not a bit-field (byte) CHAR_BIT 8"`. And 6.2.6.1: `"Values stored in non-bit-field objects of anyother object type consist of n×CHAR_BIT bits, where n is the size of an object of that type, in bytes."`
schot
When will this stupid `CHAR_BIT` argument finally die? On anything except DSPs and 30+ year old legacy mainframes, `CHAR_BIT` is 8. POSIX requires `CHAR_BIT==8`, Windows is tied to x86 where `CHAR_BIT==8`, and the whole Internet and interoperability between networked machines is built on octets. Unless you have a very unusual target (in which case your code will likely not be portable anyway), there is absolutely no point in even thinking about the possibility of `CHAR_BIT!=8`.
R..
+1  A: 

It is impossible to find a size of bit-field using sizeof(). Refer to C99:

  • 6.5.3.4 The sizeof operator, bit-field is clearly not supported by sizeof()
  • 6.7.2.1 Structure and union specifiers here it is clarified that bit-field isn't self standing member.

Otherwise, you can try to assign to the bit-field member -1u (value with all bits set) and then find the index of the most significant bit. E.g. (untested):

s.bitfield = -1u;
num_bits = ffs(s.bitfield+1)-1;

man ffs for more.

Dummy00001
+1 this is looking closer to an optimal length finder. what's `ffs()`?
eruciform
@eruciform: ffs = find first set. a function (often mapped directly to a CPU instruction) to find first bit set in the int. bits are numbered from 1. if input int is 0, then return is too 0.
Dummy00001
@dummy00001: nice! that is definitely a function i've never seen. and here i thought i had largely visited the cobweb-encrusted corners of C over the years!
eruciform
There's no (portable) way to have `ffs` computed at compile-time, so this is generally inefficient. **However**, your loops probably don't depend on the count of bits but just looping over bits, in which case you can initialize a bitfield with -1 and do something like `for (counter.bf=-1; counter.bf; counter.bf>>=1)`. (Tip: this will only work if your bitfield is `unsigned`.)
R..