Is there a bit-equivalent of sizeof() in C?
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, a开发者_如何学运维nd 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. ;-)
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.
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.
I implemented this solution[1]
#include <stdio.h>
#define bitoffsetof(t, f) \
({ union { unsigned long long raw; t typ; }; \
raw = 0; ++typ.f; __builtin_ctzll(raw); })
#define bitsizeof(t, f) \
({ union { unsigned long long raw; t typ; }; \
raw = 0; --typ.f; 8*sizeof(raw)-__builtin_clzll(raw)\
-__builtin_ctzll(raw); })
struct RGB565 { unsigned short r:5, g:6, b:5; };
int main()
{
printf("offset(width): r=%d(%d) g=%d(%d) b=%d(%d)\n",
bitoffsetof(RGB565, r), bitsizeof(RGB565, r),
bitoffsetof(RGB565, g), bitsizeof(RGB565, g),
bitoffsetof(RGB565, b), bitsizeof(RGB565, b));
}
$ gcc bitfieldtest.cpp && ./a.out
offset(width): r=0(5) g=5(6) b=11(5)
[1] https://twitter.com/suarezvictor/status/1477697986243272706
UPDATE: I confirmed this is solved at compile time:
void fill(int *x)
{
x[0]=bitoffsetof(RGB565, r);
x[1]=bitsizeof(RGB565, r);
x[2]=bitoffsetof(RGB565, g);
x[3]=bitsizeof(RGB565, g);
x[4]=bitoffsetof(RGB565, b);
x[5]=bitsizeof(RGB565, b);
}
Assembler output:
fill:
.LFB12:
.cfi_startproc
movl $0, (%rdi)
movl $5, 4(%rdi)
movl $5, 8(%rdi)
movl $6, 12(%rdi)
movl $11, 16(%rdi)
movl $5, 20(%rdi)
ret
Use a set of #define statements to specify the bitwidths in the definition of the structure, and then use the same #define when printing, or whatever.
You get the same 'define once, use many times', albeit you do have the bitfield size definitions cluttering up your global name space:
# cat p.c
#include<stdio.h>
int main( int argc, char **argv )
{
#define bitfield_sz 3
struct { unsigned int bitfield : bitfield_sz; } s;
fprintf( stdout, "size=%d\n", bitfield_sz );
}
# gcc p.c -o p
# ./p
size=3
#
精彩评论