【问题标题】:How can I create a 48-bit uint for bit mask如何为位掩码创建 48 位 uint
【发布时间】:2025-12-23 14:55:16
【问题描述】:

我正在尝试创建一个 48 位整数值。我知道可以使用 char 数组或结构,但我希望能够进行位掩码/操作,但我不确定如何做到这一点。

目前该程序使用 16 位 uint,我需要将其更改为 48。它是一个字节码解释器,我想将内存寻址扩展到 4GB。我可以只使用 64 位,但这会浪费很多空间。

以下是代码示例:

unsigned int program[] = { 0x1064, 0x11C8, 0x2201, 0x0000 };

void decode( )
{
  instrNum = (program[i] & 0xF000) >> 12; //the instruction
  reg1     = (program[i] & 0xF00 ) >>  8; //registers
  reg2     = (program[i] & 0xF0  ) >>  4;
  reg3     = (program[i] & 0xF   );
  imm      = (program[i] & 0xFF  ); //pointer to data
}

完整程序:http://en.wikibooks.org/wiki/Creating_a_Virtual_Machine/Register_VM_in_C

【问题讨论】:

  • 对于 4GB 来说 32 位不够大吗?
  • 这当然是可能的,但是如果您选择(更简单、更高效)64 位选项,那么拥有这 16 个未使用的位有那么大吗?
  • 浪费大量空间:D?你打算在什么机器上运行它? 48 = 16*3,因此您可以使用位集:3 个 16 位整数(或 6 个 8 位整数)的数组。
  • @chux:不,因为它包含字节码指令以及内存位置。
  • 建议使用 64 位 int,但创建特殊代码以有效存储它们的数组 - 删除第 4 个字节。顺便说一句:我一直使用带有嵌入式处理器的int24_tint48_t

标签: c bit-manipulation bytecode bitmask


【解决方案1】:

您可以使用通常用于表示已知固定位宽的整数类型的位域。位域的一个众所周知的用法是表示一组位和/或一系列位,称为标志。您可以对它们应用位操作。

#include <stdio.h>
#include <stdint.h>

struct uint48 {
    uint64_t x:48;
} __attribute__((packed));

【讨论】:

  • 注:1) “位域的类型应为_Boolsigned intunsigned int 或其他一些实现定义的类型的合格或非合格版本。” C11dr §6.7.2.1 5. 这个答案提出的是实现定义的行为。 2)printf( "%zu\n", sizeof(ui48));
  • @chux 正确,我已将类型更改为 uint64_t。你的观点 2) 呢? ideone.com/1nVesR
  • 1) 更改为 uint64_tunsigned long long 有关会议 C11dr §6.7.2.1 5. 2) sizeof() 返回类型 size_t,而不是 unsigned。这两种类型可能不同。 *.com/questions/940087/…
  • @chux 所以这是实现定义的,好的。这仍然有效。
  • 1) 是实现定义的。如我所见,编译器要么根据需要使用它,要么在编译时抱怨。 2)是UB。 “如果任何参数不是相应转换规范的正确类型,则行为未定义。” §7.21.6.1 9 代码将编译,但运行时结果可能有偏差。 3) 两者都不是主要问题,因为 OP 应该 能够应付。只是想指出这些以供您审查。
【解决方案2】:

uint48 数组使用具有特殊功能的结构或uint16_t 数组。

对于个别情况,请使用uint64_tunsigned long longuint64_t 对于单独的 int48 可以正常工作,但可能需要屏蔽 *&lt;&lt; 等结果操作以保持高位清除。数组只需要一些节省空间的例程。

typedef uint64_t uint48;
const uint48 uint48mask = 0xFFFFFFFFFFFFFFFFull; 

uint48 uint48_get(const uint48 *a48, size_t index) {
  const uint16_t *a16 = (const uint16_t *) a48;
  index *= 3;
  return a16[index] | (uint32_t) a16[index + 1] << 16
          | (uint64_t) a16[index + 2] << 32;
}

void uint48_set(uint48 *a48, size_t index, uint48 value) {
  uint16_t *a16 = (uint16_t *) a48;
  index *= 3;
  a16[index] = (uint16_t) value;
  a16[++index] = (uint16_t) (value >> 16);
  a16[++index] = (uint16_t) (value >> 32);
}

uint48 *uint48_new(size_t n) {
  size_t size = n * 3 * sizeof(uint16_t);
  // Insure size allocated is a multiple of `sizeof(uint64_t)`
  // Not fully certain this is needed - but doesn't hurt.
  if (size % sizeof(uint64_t)) {
    size += sizeof(uint64_t) - size % sizeof(uint64_t);
  }
  return malloc(size);
}

【讨论】: