【问题标题】:Allocate n bytes for x bits为 x 位分配 n 个字节
【发布时间】:2010-11-04 20:16:58
【问题描述】:

首先,这可以是任何语言的通用算法,但我正在学习 C,如果有一些 C 特定的功能,我想知道!

我正在编写一个函数,它将为给定的位数分配足够的内存;进入long long * 变量。位数不能为< 1。我测试了算法:

int bits;  // the function argument, checked for value > 0
size_t dataSize;  // the value passed to the malloc function

for (bits = 1; bits<100; bits++) {
   if (bits < sizeof(long long)) {
      dataSize = 1;
   } else {
      dataSize = (bits + (sizeof(long long) - (bits % sizeof(long long)))) / sizeof(long long);
   }

   printf("%d = %d\n", bits, (int) dataSize);
}

看起来不错...但丑陋:) 有什么方法可以更优雅地实现这一目标? 谢谢!

【问题讨论】:

  • 我不完全理解你的问题。你不能只做 dataSize = sizeof(int) * bits + padding 吗?除了最低限度之外,填充是您要分配的额外字节
  • 对所有答案的评论,真的,但是当有一个非常好的宏 CHAR_BIT 可以使答案更便携时,为什么要假设一个字节中有 8 位?

标签: c bit-manipulation


【解决方案1】:

假设您要将位域初始化为零,calloc() 可能比malloc() 更可取;您可能还应该使用无符号类型来避免在旋转位时进行有符号移位。

#include <limits.h>

const size_t BITS_PER_BLOCK = sizeof (long long) * CHAR_BIT;
size_t count = bits / BITS_PER_BLOCK + !!(bits % BITS_PER_BLOCK);
unsigned long long *blocks = calloc(count, sizeof *blocks);

!! 是一种将非零值转换为1 的有点骇人听闻的方法,这在 C 中很常见,如果位数不能被BITS_PER_BLOCK 整除,则在此处用于分配额外的块。

您还可以通过

获得所需数量的块(例如,Lars 在 cmets 中指出的另一个答案)
size_t count = (bits + BITS_PER_BLOCK - 1) / BITS_PER_BLOCK;

我发现前一个版本更具可读性,但由于后者也很常见——它是使用整数算术的更通用舍入算法的一个特例——C 程序员应该对任何一种选择都感到满意。

【讨论】:

  • 十进制值很可能永远不会直接使用,只有位。移位位,即使是有符号值也不会(或似乎不会)影响两种类型的位表示......还是我错过了什么?
  • @Yanick:根据架构,右移有符号值可能会插入 1 而不是 0;如果您跨块边界组合值,这可能会咬您一口,例如,如果您执行(blocks[42] &gt;&gt; x) | (blocks[43] &lt;&lt; (BITS_PER_BLOCK - x)) 之类的操作;我通常只对位数组使用无符号值,即使有符号值在大多数情况下都可以正常工作
  • 如果你还是要分裂,为什么不直接做:(bits + BITS_PER_BLOCK - 1)/BITS_PER_BLOCK?更简单,不需要两次除法操作。
【解决方案2】:

除非我遗漏了什么,否则我认为它只是:

int bits;
size_t dataSize;

dataSize = bits / (sizeof(long long) * 8);
if( bits % (sizeof(long long) * 8) ) { //Don't add 1 if it was evenly divisible
    dataSize++;
}
dataSize *= sizeof(long long)

因此假设long long 大小为 8 个字节,则值 1-64 将返回 8,65-128 将返回 16,以此类推。

【讨论】:

  • 我最初写过long long指针无关紧要,但最好确保内存的大小可以被long long的大小整除,因为它引用它时将尝试获取所有 8 个字节。
  • 我喜欢使用这种方法来一步处理'+1':'dataSize = (bits + sizeof(long long)* 8 - 1)/(sizeof(long long) * 8) ' .
  • @Lars,是的,我也喜欢那个班轮
  • 因为'-1',加法会导致被除数'溢出'到(sizeof(long long)*8)的下一个倍数,除非位数是偶数(sizeof(long long)*8) 的倍数。如果您只查看 (bits + 7)/8,然后对位值 0 到 10 进行评估,数学可能更容易理解(当我第一次看到这个公式时,这就是它的感觉)。
  • @Lars 我知道-1,我问的是反对票:)
【解决方案3】:

如果你想要n位,那么计算long long数量的正确表达式是:

int bits = n;
int items = (((bits - 1) / CHAR_BIT) / sizeof(long long)) + 1;

【讨论】:

    【解决方案4】:

    你不应该为此需要一个循环。如果您进行位 / sizeof(long long) 的除法,您应该得到四舍五入的结果。然后,您可以通过位模数 % sizeof(long long) 来检查余数,如果它不为零,则需要在结果中加一。

    【讨论】:

    • 循环仅用于测试目的。它显示了我需要多少字节来获得位数。
    【解决方案5】:
    size_t len_needed(int bits) {
       size_t x=  bits/(sizeof(long long) * 8);
       x = (bits%(sizeof(long long) * 8) ? 1 : 0;
    
       return x;
    }
    

    ? : 只是三元运算符,它是执行 if/else 计算结果的一种简短方法。

    【讨论】:

      【解决方案6】:

      这是您的代码,只是在 printf 中添加了一个新值

      int bits;  // the function argument, checked for value > 0
      size_t dataSize;  // the value passed to the malloc function
      
      for (bits = 1; bits<100; bits++) {
         if (bits < sizeof(long long)) {
            dataSize = 1;
         } else {
            dataSize = (bits + (sizeof(long long) - (bits % sizeof(long long)))) / sizeof(long long);
         }
      
         printf("%d = %d (%d)\n", bits, (int) dataSize, 1 + bits/sizeof (long long));
         /*             ^^^^^                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
      }
      

      【讨论】:

        【解决方案7】:
        Number_of_long_longs_for_x= (x + sizeof(long long) - 1)/sizeof(long long)
        

        现在,long long 中的位数是 log2(ULLONG_MAX+1),而不是 sizeof(long long)。所以你应该重新审视你的计算。

        【讨论】:

          【解决方案8】:
          #define SIZEOF_LL  sizeof(long long)
          nbytes  =  (xbits  + 8         - 1) / 8;
          nllongs =  (nbytes + SIZEOF_LL - 1) / SIZEOF_LL;
          

          或者如果你知道尺寸。

          nbytes =  (xbits  + 7) / 8;
          nllongs = (nbytes + 7) / 8;
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-02-21
            • 1970-01-01
            • 1970-01-01
            • 2010-11-19
            相关资源
            最近更新 更多