【问题标题】:Using sizeof to get maximum power of two使用 sizeof 获得两个的最大幂
【发布时间】:2012-10-10 20:52:41
【问题描述】:

在 C/C++ 中有没有一种方法可以使用 sizeof 运算符计算某种数据类型可表示的 2 的最大幂?

例如,假设我有一个unsigned short int。它的值可以在065535 之间。 因此,unsigned short int 可以包含的最大 2 次方是 32768

我将这个unsigned short int 传递给一个函数,我(目前)和算法看起来像这样:

if (ushortParam > 32768) {
    ushortParam = 32768; // Bad hardcoded literals
}

但是,将来我可能想更改变量类型以合并更大的 2 次幂。是否有使用 sizeof() 的与类型无关的公式可以实现以下目标:

if (param > /*Some function...*/sizeof(param) )
{
    param = /*Some function...*/sizeof(param);
}

请注意,该参数永远不需要浮点精度 - 仅限整数。

【问题讨论】:

  • 这是你可以使用 std::numeric_limits 做的事情吗?

标签: c++ c types sizeof


【解决方案1】:

接受的答案可能适用于 Posix 平台,但不是通用的 C/C++。它假定 CHAR_BIT 为 8,不指定类型,并假定该类型没有填充位。

以下是任何/所有无符号整数类型的更通用版本,不需要包含任何标头、依赖项等:

#define MAX_VAL(UNSIGNED_TYPE) ((UNSIGNED_TYPE) -1)

#define MAX_POW2(UNSIGNED_TYPE) (~(MAX_VAL(UNSIGNED_TYPE) >> 1))

#define MAX_POW2_VER2(UNSIGNED_TYPE) (MAX_VAL(UNSIGNED_TYPE) ^ (MAX_VAL(UNSIGNED_TYPE) >> 1))

#define MAX_POW2_VER3(UNSIGNED_TYPE) ((MAX_VAL(UNSIGNED_TYPE) >> 1) + 1)

标准,甚至 C90,保证将 -1 强制转换为无符号类型总是产生该类型可以表示的最大值。从那里开始,上面的所有按位运算符都定义良好。

http://c0x.coding-guidelines.com/6.3.1.3.html

6.3.1.3 有符号和无符号整数

682 当整数类型的值转换为_Bool以外的其他整数类型时,如果该值可以用新的类型表示,则保持不变。

683 否则,如果新类型是无符号的,则在新类型可以表示的最大值的基础上反复加减一,直到值在新类型的范围内.

684 否则,新类型有符号,值不能在其中表示;

685 结果是实现定义的,或者引发了实现定义的信号。

无符号类型的最大值是 2 的幂次方小 1,并且所有值位都已设置。上面的表达式只设置了最高位,这是该类型可以表示的最大 2 次方。

http://c0x.coding-guidelines.com/6.2.6.2.html

6.2.6.2 整数类型

593 对于 unsigned char 以外的无符号整数类型,对象表示的位应分为两组:值位和填充位(后者不需要任何一个)。

594 如果有 N 个值位,每个位应表示 1 和 2^(N - 1) 之间的 2 的不同幂,因此该类型的对象应能够表示从 0 到 2^N 的值 - 1 使用纯二进制表示;

595 这应该称为值表示。

596 未指定任何填充位的值。

【讨论】:

    【解决方案2】:

    要获得某个整数类型可表示的 2 的最大幂,您可以使用 limits.h 而不是 sizeof 运算符。例如:

    #include <stdlib.h>
    #include <stdio.h>
    #include <limits.h>
    
    int main() {
    
      int max   = INT_MAX;
      int hmax  = max>>1;
      int mpow2 = max ^ hmax;
    
      printf("The maximum representable integer is %d\n",max);
      printf("The maximum representable power of 2 is %d\n",mpow2);
      return 0;
    }
    

    这应该始终有效,因为始终定义了正整数的右移。引用标准 C 第 6.5.7.5 节(按位移位运算符):

    E1 >> E2的结果是E1右移E2位位置。如果 E1 有一个无符号类型,或者如果 E1 有一个有符号类型和一个非负数 值,结果的值是商的整数部分 E1除以数量,2的幂E2

    如果必须使用sizeof,您可以使用:

    1 << (CHAR_BIT*sizeof(param)-1)
    

    对于无符号整数类型和:

    1 << (CHAR_BIT*sizeof(param)-2)
    

    用于有符号整数类型。上面的行仅适用于整数类型没有填充位。确保这些线路正常工作的标准 C 部分在第 6.2.6.2 节中。特别是:

    对于 unsigned char 以外的无符号整数类型, 对象表示应分为两组:值位和 填充位(不需要任何后者)。如果有 N 值位,每个位应代表 1 之间的 2 的不同幂 和 2N-1,以便该类型的对象能够 使用纯二进制表示从 0 到 2N - 1 的值 表示;这应该称为值表示。

    保证第一个方法工作时:

    对于有符号整数类型,对象表示的位应 分为三组:值位、填充位和符号 少量。不需要任何填充位;应该有一个 符号位。

    ...

    有符号整数类型的有效(非陷阱)对象表示 其中符号位为零是一个有效的对象表示 对应的无符号类型,代表相同的值。

    解释为什么第二行给出正确答案。

    【讨论】:

    • 在 C++ 中,尤其是在模板中,使用std::numeric_limits&lt;T&gt; 更为惯用,它提供(以及其他)min()max() 函数。
    • @MatthieuM。我打算给出一个与C语言相关的答案。如果您认为是这种情况,我将编辑答案以使其清楚(即使我认为引用 C 标准就足够了)。
    • 只是为了迂腐:如果param 的类型有填充位,sizeof 变体将失败。最好将它添加到第一个方法,因为TYPE_MAX 必须是2^N - 1,其中N 是类型中的值位数,每个 6.2.6.2。
    【解决方案3】:

    怎么样:

    const T max_power_of_two = (std::numeric_limits<T>::max() >> 1) + 1;
    

    【讨论】:

      【解决方案4】:

      设置该参数大小的变量的最高有效位将为您提供 2 的最高幂。

      1 << (8*sizeof(param)-1)
      

      【讨论】:

      • sizeof 以字节为单位:您需要乘以CHAR_BIT 来设置相应的位。
      • 不是8,而是CHAR_BIT(通常是8,不一定总是)更好。
      • 您将 C 字节与字节(=8 位)的最常见含义混淆了。 C 字节可以合法地包含超过 8 位。阅读一本关于 C 或 C 标准的好书。
      • 我们可以假设一个字节是 8 位,否则这可能无论如何都行不通。就像在奇数硬件上一样,并非所有位都是值表示的一部分。想想旧的超级计算机将整数存储在浮点寄存器中。
      • 正如其他人所指出的,硬编码 8 是错误的,您确实想将 1 强制转换为您尝试生成的类型,如果该类型有任何填充位,这将不起作用。
      猜你喜欢
      • 2014-07-20
      • 2020-07-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-28
      • 2019-10-07
      • 2012-01-08
      相关资源
      最近更新 更多