【问题标题】:Split parts of a uint32_t hex value into smaller parts in C++在 C++ 中将 uint32_t 十六进制值的一部分拆分为更小的部分
【发布时间】:2017-04-30 21:25:00
【问题描述】:

我有一个 uint32_t 如下:

uint32_t midiData=0x9FCC00;

我需要把这个 uint32_t 分成更小的部分,这样 9 就变成了它自己的实体,F 变成了它自己的实体,CC 变成了它自己的实体。如果您想知道我在做什么,我正在尝试分解 MIDI 消息的各个部分,以便在我的程序中更容易管理它们。

我找到了this solution,但问题是我不知道如何将它应用到 CC 部分,而且我不确定这种方法是否适用于 C++。

这是我目前所拥有的:

uint32_t midiData=0x9FCC00;

uint32_t status = 0x0FFFFF & midiData; // Retrieve 9
uint32_t channel = (0xF0FFFF & midiData)>>4; //Retrieve F
uint32_t note = (0xFF00FF & midiData) >> 8; //Retrieve CC

这对 C++ 是否正确?我问的原因是因为我以前从未使用过 C++,它使用 > 和

【问题讨论】:

  • 你试过了吗?成功了吗?

标签: c++ hex midi uint32-t


【解决方案1】:

您也可以在 C++ 中使用位移运算符 >> 和位掩码运算符 &。 但是,如何使用它存在一些问题:

运算符v1 & v2 给出一个从v1v2 中设置的位构建的数字,例如,0x12 & 0xF0 给出0x10,而不是0x02。此外,位移运算符采用位数,十六进制数中的单个数字(通常称为半字节)由 4 位组成(0x0..0xF 需要 4 位)。所以,如果你有0x12 并且想得到0x01,你必须写0x12 >>4。 因此,您的班次也需要调整:

#define BITS_OF_A_NIBBLE 4

unsigned char status = (midiData & 0x00F00000) >> (5*BITS_OF_A_NIBBLE);
unsigned char channel = (midiData & 0x000F0000) >> (4*BITS_OF_A_NIBBLE);
unsigned char note = (midiData & 0x0000FF00) >> (2*BITS_OF_A_NIBBLE);
unsigned char theRest = (midiData & 0x000000FF);

【讨论】:

  • 这完全符合我的需要,我只需要使用 uint8_t、uint16_t 或 uint32_t。它对 uint_t 是否同样有效?
  • 是的,只要您注意不要移动比相应数据类型提供的更多位,并且只要您不将 a 分配给较大的值;即uint8_t x = (midiData & 0xFF000000) >> 4 是一个问题,因为 RHS 的结果不适合 8 位值,uint8_t y = 0xFF;y >> 10 是一个问题,因为您移动的位数比y 的位数多。
【解决方案2】:

在某种程度上,你有它倒退。

在布尔逻辑中(& 是按位与),与 0 的东西将排除它。知道十六进制的F 是二进制的1111,像0x9FCC00 & 0x0FFFFF 这样的行将为您提供除9 之外的所有十六进制数字,这与您想要的相反。

所以,对于状态:

uint32_t status = 0xF000000 & midiData; // Retrieve 9

实际上,这将为您提供 0x900000。如果你想要 0x9(十进制也是 9),你需要将结果移位。

现在,右移位运算符(比如 X >> 4)意味着将 X 向右移动 4 位;除以 16。那是 4 位,而不是 4 个十六进制数字。 1 个十六进制数字 == 4 位,所以要从 0x900000 得到 9,您需要 0x900000 >> 20

所以,把它们放在一起,得到一个 9 的状态:

uint32_t status = (0xF000000 & midiData) >> 20;

类似的过程会得到你想要的剩余值。

【讨论】:

    【解决方案3】:

    一般来说,我建议先换档,然后再戴口罩——这样更不容易出错:

    uint8_t cmd = (midiData >> 16) & 0xff;
    uint8_t note = (midiData >> 8) & 0x7f;     // MSB can't be set
    uint8_t velocity = (midiData >> 0) & 0x7f; // ditto
    

    然后拆分cmd变量:

    uint8_t status = (cmd & 0xf0);             // range 0x00 .. 0xf0
    uint8_t channel = (cmd & 0x0f);            // range 0 .. 15
    

    我个人不会费心将 status 值映射回 0 .. 15 范围内 - 通常理解为,例如0x90 是“注释”,而不是普通值 9

    【讨论】:

      猜你喜欢
      • 2020-12-06
      • 2019-03-27
      • 1970-01-01
      • 2011-02-10
      • 1970-01-01
      • 2013-10-22
      • 1970-01-01
      • 2012-05-28
      • 1970-01-01
      相关资源
      最近更新 更多