【问题标题】:Reading bits from the bin value从 bin 值中读取位
【发布时间】:2020-11-30 21:10:09
【问题描述】:

从 bin 值中读取位的顺序是什么?拥有例如this official MS doc 网站关于lParamWM_CHAR 消息,他们解释了哪些位有什么含义。将 16-23 位作为 扫描码 值,我应该从右到左读取这些位,反之亦然?

【问题讨论】:

  • 这和汇编有什么关系?
  • 您的问题是关于 WM_CHAR 还是任何二进制数据块?因为这是两个完全不同的问题。在 Winapi 编程中,您将在 lParam 等上使用 HIWORDLOWORD 宏,而无需过多关注底层二进制表示。因此 API。
  • 重复的,但我投票决定重新打开,因为@TedLyngmo 的解释更加清晰。此外,这个问题的措辞要好得多。我希望将另一个问题作为指向这个问题的重复问题关闭。
  • 我不能投票关闭另一个,因为不允许循环,但是伙计们,我随时都会交换它们!

标签: c++ c memory bit


【解决方案1】:

两种方式:

UINT bitsxtractBits(UINT val, int startBit, int nbits)
{
    UINT mask = ((UINT)1 << nbits) - 1;

    return (val & mask) >> startBit;
}

//note it will not work if you want to extract all bits (in this case 32). 
//but in this case you do not need to extract them :)

以及提取位元的用法:

bitsxtractBits(message, 16, 8)

union WM_CHAR_message
{
    struct 
    {
        UINT    repatCount : 16;
        UINT    scanCode   : 8;
        UINT    : 4;
        UINT    contextCode : 1;
        UINT    previousState : 1;
        UINT    transitionState : 1;
    };
    UINT  raw;
};

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    union WM_CHAR_message msgu;
    //C++ safe
    memcpy(&msgu, &message, sizeof(msgu));  // will be optimized to the store instruction only
    switch (message)
    {
   
    // ...

    case WM_CHAR:
        switch(msgu.scanCode)
        {
            //....
        }
        OnKeyPress(wParam);
        break;

    default:
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
}

【讨论】:

  • 注意:在 C++ 中,写入一个联合成员然后从另一个成员读取是未定义的行为,并且禁止匿名结构。指定初始化器仅适用于 C++20 及更高版本。
  • @TedLyngmo 确实 - 已修改
【解决方案2】:

您链接到的页面使用LSB 0 bit numbering,因此您可以提取第 16-23 位

lParam & 0b00000000111111110000000000000000U
//         |       |      |               |
// bit    31      23     16               0
//        MSB                            LSB

注意:二进制数的 0b 前缀需要 C++14。在 C 中,它仅在某些实现中作为扩展提供。

你可能还想用

来下移结果
(lParam & 0b00000000111111110000000000000000U) >> 16U

或更简单

(lParam >> 16U) & 0b11111111U //  or  (lParam >> 16U) & 0xFFU

【讨论】:

  • 谢谢。所以这些位是从右到左的顺序索引的,当他们说例如位 #3 表示 0b0000'0101 值 - 从右侧算起第二个 "1"
  • @DarosRT10 不客气。它使用LSB 0 bit numbering,因此,bit0 是第一个1,bit2 是第二个1
  • 注意需要 C++14 或更新版本或 gcc 系列编译器。在 C 0b 表示法中是 gcc 扩展
  • @P__J__ 确实如此。我没想过要提这个。现代 Visual Studio 版本默认为 C++14。添加了注释。谢谢。
猜你喜欢
  • 2020-12-29
  • 2011-08-06
  • 2018-11-30
  • 2021-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多