【问题标题】:Number of bits in a data type数据类型中的位数
【发布时间】:2010-01-19 02:56:52
【问题描述】:

我有两个分配任务,一个返回任何机器上 int 类型的位数。我想我会这样写我的函数:

int CountIntBitsF() {
    int x = sizeof(int) / 8;
    return x;
}

看起来对吗?

第二部分是用宏返回任意数据类型任意位的个数,宏可以取自limits.h。我在我的机器上查找了limits.h,还查找了http://www.opengroup.org/onlinepubs/007908799/xsh/limits.h.html,但我认为我并不真正理解其中任何一个将如何返回任何数据类型的位数。有什么想法吗?谢谢。

【问题讨论】:

标签: c sizeof


【解决方案1】:

The fundamental unit of storage is a char。它并不总是 8 位宽。 CHAR_BIT 在limits.h 中定义,具有char 中的位数。

【讨论】:

    【解决方案2】:

    这是*,而不是/

    至于第二部分,请参阅“数值限制”部分。

    【讨论】:

      【解决方案3】:

      如果您想要用于在内存中存储 int 的位数,请使用 Justin 的答案 sizeof(int)*CHAR_BIT。如果您想知道值中使用的位数,请使用 slebetman 的答案。

      虽然要获取 INT 中的位,但您可能应该使用 INT_MAX 而不是 UINT_MAX。我不记得 C99 是否真的保证 intunsigned int 具有相同的宽度,或者只是它们具有相同的存储大小。我只怀疑后者,因为在 6.2.6.2 中我们有“如果有符号类型中有 M 值位,无符号类型中有 N,则 M

      实际上,整数类型在我使用的任何实现中都没有填充位,因此您很可能得到相同的答案,符号位为 +/- 1。

      【讨论】:

      • C99 草案 (6.2.5.6) 的另一句话:对于每个有符号整数类型,都有一个对应的(但不同的)无符号整数类型(用关键字 unsigned 指定),它使用相同的存储量(包括标志信息)并具有相同的对齐要求。
      • 谢谢。并注意“相同数量的存储空间”,而不是“相同数量的非填充位”。
      • 为什么我们需要知道内存中的 int 与值中使用的位之间的区别。如果您正在执行某种硬件编程,您需要知道用于表示某些寄存器值或类似内容的位数,那么值中使用的位是否更重要?
      • 是的,有很多重要的原因需要关心 int 的位宽。一方面,它决定了可以存储多大的值(即,有符号的 16 位 int 可以存储 -32768..32767,而无符号的 16 位 int 可以存储 0..65535 等等)。如果您需要对数据进行序列化(即保存到文件或通过网络传输),这也很重要。
      【解决方案4】:

      limits.h 中,UINT_MAX 是 unsigned int 类型对象的最大值。这意味着它是一个所有位都设置为 1 的 int。因此,计算 int 中的位数:

      #include <limits.h>
      
      int intBits () {
          int x = INT_MAX;
          int count = 2; /* start from 1 + 1 because we assume
                          * that sign uses a single bit, which
                          * is a fairly reasonable assumption
                          */
      
          /* Keep shifting bits to the right until none is left.
           * We use divide instead of >> here since I personally
           * know some compilers which does not shift in zero as
           * the topmost bit
           */
          while (x = x/2) count++;
      
          return count;
      }
      

      【讨论】:

      • 这样的编译器违反了标准,fwiw。
      • @slebetman:您可能正在考虑转移 signed 值。对于无符号类型,移位是明确定义的。
      • 必须记住,源代码是由编译器转换为机器语言的,而不是由指定它们的文档。
      • @slebetman:从技术上讲,这不是标准的扩展,只是违反,因此该模式下的编译器不是 C 编译器,它是与 C 非常相似的其他语言的编译器。否则,Java 是 C 标准的“扩展”,通过在 C 中添加和删除规则,直到您最终使用 Java ;-)。 C 标准的扩展是当您采用不合法的 C 语言并定义它在您的实现中的作用时。它不影响合法的 C.
      • @slebetman:“有符号整数和无符号整数具有相同的位数”。我在标准中找不到,你知道它在哪里说明吗?如果在我的实现中 sizeof(unsigned int) == 4, UINT_MAX == 0xFFFFFFFF, sizeof(int) == 4, INT_MAX == 0x3FFFFFFF 和 int 有一个填充位,我认为没有充分的理由,我应该打破什么规则除了 lulz 吗?
      【解决方案5】:

      使用 g++ -O2,此函数计算为内联常量:

      #include <climits>
      #include <stddef.h>
      #include <stdint.h>
      #include <cstdio>
      
      template <typename T>
      size_t num_bits()
      {
          return sizeof (T) * (CHAR_BIT);
      }
      
      int main()
      {
          printf("uint8_t : %d\n", num_bits<uint8_t>());
          printf("size_t : %d\n", num_bits<size_t>());
          printf("long long : %d\n", num_bits<long long>());
          printf("void* : %d\n", num_bits<void*>());
          printf("bool : %d\n", num_bits<bool>());
          printf("float : %d\n", num_bits<float>());
          printf("double : %d\n", num_bits<double>());
          printf("long double : %d\n", num_bits<long double>());
      
          return 0;
      }
      

      输出:

      uint8_t : 8
      size_t : 32
      long long : 64
      void* : 32
      bool : 8
      float : 32
      double : 64
      long double : 96
      

      生成的 X86 32 位汇编:

      ---剪辑---

      movl    $32, 8(%esp)      <--- const $32
      movl    $.LC1, 4(%esp)
      movl    $1, (%esp)
      call    __printf_chk
      movl    $64, 8(%esp)      <--- const $64
      movl    $.LC2, 4(%esp)
      movl    $1, (%esp)
      call    __printf_chk
      

      ---剪辑---

      【讨论】:

        【解决方案6】:

        您确定要位数而不是字节数吗?在 C 中,对于给定类型 T,您可以使用 sizeof 运算符找到它占用的字节数。一个字节的位数为CHAR_BIT,通常为8,但可以不同。

        因此,给定T 类型,T 类型对象中的位数为:

        #include <limits.h>
        size_t nbits = sizeof(T) * CHAR_BIT
        

        请注意,除了unsigned char 类型之外,上述nbits 位的所有可能组合都可能不代表T 类型的有效值。

        对于第二部分,请注意您可以将sizeof 运算符应用于对象和类型。换句话说,给定一个 T 类型和一个此类类型的对象 x

        T x;
        

        你可以通过sizeof(T)找到T的大小,通过sizeof x找到x的大小。如果 sizeof 用于对象,则括号是可选的。

        鉴于以上信息,您应该能够回答您的第二个问题。如果仍有问题,请再次询问。

        【讨论】:

          【解决方案7】:

          您的公式不正确:您不应将sizeof(int) 除以8,而应将int (sizeof(int)) 中的字节数乘以字节中的位数,这确实在&lt;limits.h&gt; 作为宏 CHAR_BIT 的值。

          这里是修正后的函数:

          #include <limits.h>
          
          int CountIntBitsF(void) {
              return sizeof(int) * CHAR_BIT;
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2022-06-17
            • 2013-10-15
            • 2010-10-29
            • 1970-01-01
            • 2019-05-14
            • 2013-09-05
            • 2014-11-09
            相关资源
            最近更新 更多