31

Sizeof() 在应用于位域时不起作用:

# 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

...显然,因为它不能返回浮点部分大小或其他东西。然而,它提出了一个有趣的问题。在 C 语言中是否有等价物可以告诉您变量/类型中的位数?理想情况下,除了位域之外,它也适用于常规类型,例如charint 。

更新:

如果位域没有与 sizeof() 等效的语言,那么计算它的最有效方法是什么——在运行时!想象一下,您有依赖于此的循环,并且如果您更改位域的大小,您不希望它们中断 - 并且没有公平的作弊并使位域大小和循环长度成为宏。;-)

4

4 回答 4

24

您无法确定 C 中位域的大小。但是,您可以使用 中的 的值找出其他类型的位CHAR_BIT大小<limits.h>。比特的大小很简单CHAR_BIT * sizeof(type)

不要假设 C 字节是八位字节,它至少是8 位。有 16 甚至 32 位字节的实际机器。

关于你的编辑: 我会说一个位域int a: n;的大小定义为n位。放入结构时的额外填充位属于结构而不是位域。

我的建议:不要使用位域,而是使用(数组)unsigned char并使用位掩码。这样,很多行为(溢出,无填充)都得到了很好的定义。

于 2010-07-23T15:57:23.607 回答
5

使用 sizeof() 无法找到位域的大小。参考C99:

  • 6.5.3.4 The sizeof operator, sizeof() 显然不支持位域
  • 6.7.2.1 Structure and union specifiers这里澄清了位域不是独立的成员。

否则,您可以尝试分配给位域成员 -1u(所有位设置的值),然后找到最高有效位的索引。例如(未经测试):

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

man ffs更多。

于 2010-07-23T16:27:51.873 回答
1

我实施了这个解决方案[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

更新:我确认这是在编译时解决的:

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);
}

汇编器输出:

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
于 2022-01-02T18:08:48.213 回答
0

使用一组#define 语句来指定结构定义中的位宽,然后在打印时使用相同的#define 或其他。

您会得到相同的“定义一次,多次使用”,尽管您的位域大小定义会弄乱您的全局名称空间:

# 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
#
于 2022-02-04T18:56:23.190 回答