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

发布于 2024-12-09 20:37:00 字数 139 浏览 0 评论 0原文

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

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

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

For example,if the integer is less than 255,than it can be restored in 1 byte,

if it's greater than 255,it requires at lest 2 bytes.

How to write such a BYTES_REQUIRED(i) macro?

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

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

发布评论

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

评论(4

美人迟暮 2024-12-16 20:37:00

如果您使用的是 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

If you are using a C99 compiler make the cast below to (unsigned long long).
Also you can (and should) extend the construct to 8 or 16 bytes (that's left as an exercise)

#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
清风不识月 2024-12-16 20:37:00

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

#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 位作为已用空间。这需要另一个条件来解释(例如,如果为负,则否定)。

This uses an efficient divide and conquer approach:

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

If you don't mind eliminating the odd case of 3 bytes, which has no primitive type that matches it, do:

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

Be warned neither one of these handles negative numbers, since it sees the sign extended 1 bits as used space. This requires another conditional to account for (e.g. if negative, negate).

酷炫老祖宗 2024-12-16 20:37:00

您实际上需要计算 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?: 了解最大支持的整数类型的大小...其他人已经描述了此方法。

You effectively need to calculate log2(i). There's no trivial way of doing that portably, quickly, for the maximum integer value supported by the compiler and with a macro.

Options:

1.Calculate the logarithm in a loop:

// 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.Use an intrinsic function (effectively, a dedicated CPU instruction) of the compiler, if available. For 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.Use if or ?: knowing the size of the biggest supported integer type... Others have described this method already.

一杆小烟枪 2024-12-16 20:37:00

不幸的是,您要求使用 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 提到的位扫描。

Unfortunately you asked for a C macro, because this C++ templated function could have been helpful (it should work for any integer type supported by your compiler).

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;
}

Another approach that should be faster (because it's branchless), if you don't just need compile-time evaluation, is the bitscan that was mentioned by Alex.

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