'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, 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. ;-)
Solution 1:[1]
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 specifiershere 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.
Solution 2:[2]
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
Solution 3:[3]
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
#
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Dummy00001 |
| Solution 2 | |
| Solution 3 | Mac |
