C 中是否有 sizeof() 的位等效项?

发布于 2024-09-11 07:27:31 字数 646 浏览 13 评论 0原文

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() 等效的语言,那么最有效的计算方法是什么 - 在运行时!想象一下,您有依赖于此的循环,并且您不希望它们在更改位字段的大小时中断 - 并且没有公平的作弊行为并将位字段大小和循环长度设置为宏。 ;-)

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

挖个坑埋了你 2024-09-18 07:27:31

您无法确定 C 中位字段的大小。但是,您可以使用 中找到的 CHAR_BIT 值找出其他类型的位大小;。以位为单位的大小就是 CHAR_BIT * sizeof(type)

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

关于您的编辑:
我想说,根据定义,位字段 int a: n; 的大小为 n 位。放入结构体中时的额外填充位属于该结构体,而不属于位字段。

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

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.

年华零落成诗 2024-09-18 07:27:31

使用 sizeof() 不可能找到位域的大小。参考 C99:

  • 6.5.3.4 The sizeof 运算符,sizeof() 显然不支持位域
  • 6.7.2.1 结构和联合说明符 这里澄清了 bit-字段不是独立成员。

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

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

man ffs 了解更多。

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.

你的呼吸 2024-09-18 07:27:31

我实现了这个解决方案[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.输出

偏移(宽度): 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

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
耳钉梦 2024-09-18 07:27:31

使用一组#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
#

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
#
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文