【问题标题】:Is there a bit-equivalent of sizeof() in C?C 中是否存在与 sizeof() 等效的位?
【发布时间】:2011-03-20 04:22:45
【问题描述】:

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

【问题讨论】:

  • 很确定结构的布局是在编译时确定的。因此,虽然原则上它可以在运行时检查(尽管 C 没有提供这样做的方法,如果我正确阅读下面的答案),一旦编译发生(使用特定平台上的特定编译器;当然,它可能会因编译器和平台、基于字边界优化等而有所不同。

标签: c sizeof bit-fields


【解决方案1】:

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

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

关于您的修改: 我会说位域int a: n; 根据定义具有 n 位的大小。放入结构体时的额外填充位属于结构体而不是位域。

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

【讨论】:

  • +1 酷,不知道 CHAR_BIT。如果您需要在运行时计算位域大小怎么办?
  • 这是不可能的(人们避免使用位域的原因之一)。编译器可以将其作为扩展来实现,但我从未听说过。
  • @Dummy00001:对不起,你错了。 C99 标准为 CHAR_BIT 提供了一个下限为 8。并且在附录 J 3.4 中明确指出 实现定义行为 “一个字节中的位数。 "
  • @Dummy00001:我同意机器字节!= C 字节。但是 char 并不总是 8 位。 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." 然后显示:"- number of bits for smallest object that is not a bit-field (byte) CHAR_BIT 8"。和 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."
  • 这个愚蠢的CHAR_BIT 论点什么时候会死?除了 DSP 和 30 多年的旧式大型机之外,CHAR_BIT 是 8。POSIX 需要 CHAR_BIT==8,Windows 与 x86 相关联,CHAR_BIT==8,整个 Internet 和联网机器之间的互操作性都建立在八位字节上。除非您有一个非常不寻常的目标(在这种情况下,您的代码可能无论如何都不能移植),否则考虑CHAR_BIT!=8 的可能性是绝对没有意义的。
【解决方案2】:

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

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

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

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

man ffs 了解更多。

【讨论】:

  • +1 这看起来更接近最佳长度查找器。 ffs() 是什么?
  • @eruciform: ffs = 找到第一组。一个函数(通常直接映射到 CPU 指令),用于查找 int 中设置的第一位。位从 1 开始编号。如果输入 int 为 0,则返回也为 0。
  • 不错!这绝对是我从未见过的功能。在这里,我认为这些年来我主要参观了 C 的蜘蛛网结满的角落!
  • 没有(便携式)方法可以在编译时计算ffs,因此这通常效率低下。 但是,您的循环可能不依赖于位数,而只是在位上循环,在这种情况下,您可以使用 -1 初始化位域并执行for (counter.bf=-1; counter.bf; counter.bf&gt;&gt;=1) 之类的操作。 (提示:这仅在您的位域为 unsigned 时才有效。)
  • 请注意,ffs 是一个 POSIX 函数,并非在所有平台上都可用,也不适用于大于 int 的数据类型。当然,您可以推出自己的实现,但这会有点慢。
猜你喜欢
  • 2011-03-10
  • 1970-01-01
  • 2010-12-04
  • 2020-02-07
  • 2021-04-26
  • 2011-11-08
  • 2023-03-14
  • 2018-11-20
  • 2020-11-15
相关资源
最近更新 更多