如何获得用宏存储整数值所需的最少字节数?

时间:2011-10-15 09:10:41

标签: c macros

例如,如果整数小于255,则可以在 1 字节中恢复,

如果大于255,则需要至少 2 字节。

如何编写这样的BYTES_REQUIRED(i)宏?

4 个答案:

答案 0 :(得分:0)

如果您使用的是C99编译器,请将下面的强制转换为(unsigned long long)。 您也可以(并且应该)将构造扩展为8或16个字节(作为练习留下)

#include <limits.h>

#define BYTES_REQUIRED(i)                            \
           !((unsigned long)(i) >>     CHAR_BIT) ? 1 \
         : !((unsigned long)(i) >> 2 * CHAR_BIT) ? 2 \
         : !((unsigned long)(i) >> 3 * CHAR_BIT) ? 3 \
         :                                         4

答案 1 :(得分:0)

这采用了一种有效的分而治之的方法:

#define BYTES_REQUIRED(i) (((i) & 0xFFFF0000) ? (((i) & 0xFF000000) ? 4 : 3) : (((i) & 0xFF00) ? 2 : 1))

如果你不介意消除3个字节的奇怪情况,它没有与之匹配的原始类型,请执行:

#define BYTES_REQUIRED(i) (((i) & 0xFFFF0000) ? 4 : (((i) & 0xFF00) ? 2 : 1))

请注意,这些中的任何一个都不会处理负数,因为它会将符号扩展为1位作为已用空间。这需要另一个条件来解释(例如,如果否定,否定)。

答案 2 :(得分:0)

您实际上需要计算log2(i)。对于编译器和宏支持的最大整数值,没有简单的方法可以快速地进行。

选项:

1.计算循环中的对数:

// 64+-bit version:
unsigned long BYTES_REQUIRED(unsigned long long i)
{
  unsigned long bits = 0;
  while (i)
  {
    i >>= 1;
    bits++;
  }
  if (bits == 0) bits = 1;
  return (bits + 7) / 8; // we're assuming that byte=8 bits, but CHAR_BIT may be > 8
}

2.如果可用,使用编译器的内部函数(实际上是专用CPU指令)。对于MSVC ++:

// 64-bit version, not available for 32-bit code:
unsigned long BYTES_REQUIRED(unsigned long long i)
{
  unsigned long index;
  if (_BitScanReverse64(&index, i) == 0)
  {
    index = 1;
  }
  return (index + 8) / 8;
}

// 32-bit version, available for 32 and 64-bit code:
unsigned long BYTES_REQUIRED(unsigned long i)
{
  unsigned long index;
  if (_BitScanReverse(&index, i) == 0)
  {
    index = 1;
  }
  return (index + 8) / 8;
}

// 64-bit version available for 32 and 64-bit code:
unsigned long BYTES_REQUIRED(unsigned long long i)
{
  unsigned long index;
  if (_BitScanReverse(&index, (unsigned long)(i >> 32)))
  {
    index += 32;
  }
  else if (_BitScanReverse(&index, (unsigned long)i) == 0)
  {
    index = 1;
  }
  return (index + 8) / 8;
}

3.使用if?:知道支持的最大整数类型的大小......其他人已经描述了这种方法。

答案 3 :(得分:0)

不幸的是你要求一个C宏,因为这个C ++模板化的函数可能有用(它适用于你的编译器支持的任何整数类型)。

template <typename T> int bytesRequired(T value) {
  boost::function_requires< boost::IntegerConcept<T> >();
  for (int i=0; i<=sizeof(T); i++, value/=256)
    if (value == 0) return i;
}

另一种应该更快的方法(因为它是无分支的),如果你不需要编译时评估,那就是Alex提到的位扫描。