用于解压缩和将值打包到一个int

时间:2017-09-07 16:06:14

标签: c macros bit-manipulation

终于明白了什么是错的。这是我的大脑

可能是今年最糟糕的尴尬......评论do you understand how binary operators work?是正确的。

A >> 2 #shifts the value of A to right by 2 bits

而且所有这些时间,多年来,我认为2在上面的情况下被A的值移动了!!

对于这个愚蠢的问题感谢大家,感谢你纠正我的愚蠢和你的宽容和善意,非常感谢。

原帖

我正在尝试了解DIY键盘固件的一部分如何工作。固件称为qmk:https://github.com/qmk/qmk_firmware

我不确定,但代码是一个名为AVR c的c变种。

代码的作用是什么?

C macro在保持时更改键盘图层,就像功能键一样,并在快速点击时将隐藏使用ID发送到pc。

代码

图层的初始值是1到32之间的小数 kc是任何一个隐藏使用ID。

#define QK_LAYER_TAP          = 0x4000
#define LT(layer, kc) (kc | QK_LAYER_TAP | ((layer & 0xF) << 8))
#define ACTION_LAYER_TAP_KEY(layer, key) ACTION_LAYER_TAP((layer), (key))
#define ACTION_LAYER_TAP(layer, key)  (ACT_LAYER_TAP<<12 | (layer)<<8 | (key))

在循环中的另一个文件中,当用户按下可能LT(2,KC_A)绑定的键时,会触发下面的内容。

case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
    action.code = ACTION_LAYER_TAP_KEY((keycode >> 0x8) & 0xF, keycode & 0xFF);
    break;

会发生什么

因此,对于LT(2,KC_A),此宏#define LT(layer, kc) (kc | QK_LAYER_TAP | ((layer & 0xF) << 8))会产生04 | 0x4000 | ((2 & 0xf) << 8)

KC_A -> 101
0x8 -> 00001000
0xf -> 00001111
0x4000->100000000000000
2&0xf -> 00000010
((2&0xf)<<8) -> 1000000000

固件检测到0x4000位掩码并调用上面的case QK_LAYER_TAP,然后出现一些源自LT宏的幻数键码。

LT(2,04)密码为(keycode >> 0x8) & 0xF产生2,密码为keycode & 0xff产生4。

问题(编辑,因为没有人理解我)

keycode包含来自LT宏调用的第一个和第二个参数的int16中的位序列。

  • 第一个参数是0到36之间的数字,当然是用户定义的值。
  • 第二个参数是隐藏使用ID中的任何一个,范围从0到231.

由于评估表达式keycode & 0xff会产生传递给LT的hid使用id,很明显keycode包含前8位中LT的第二个参数。

到目前为止一切都很清楚。但是......

(keycode >> 0x8) & 0xF产生TL的第一个参数。

  • 0x8是00001000
  • 将上面向右移动4 4 >> 0x8导致零...
    <击> 由于密钥代码的低位正在使用中,只能修改高8位,隐藏使用id可以是一个大数字,上面表达式的预期输出是正数!
    唯一的方法似乎是some negative value >> 0x8并且可以做到,但我无法理解如何在不触及低8位的情况下操纵(keycode >> 0x8) & 0xF的值。

2 个答案:

答案 0 :(得分:1)

您正在处理驱动硬件的固件。移动一些位并与其他位置进行“或”将创建硬件寄存器的内容,在这种情况下显然是硬件配置寄存器。

需要输入位标志,移位值等,以匹配寄存器的格式,该寄存器包含大量信息,每个信息位于特定位置的一个或多个位。

要明确了解这是做什么的,您需要了解有关hw / sw接口的详细信息,这可能不会即将发布。

现在,针对您的具体问题。你写道:

  

将上面的内容向右移动4 4 >> 0x8会导致零...

这是将键码8位向右移位,而不是通过键码位移位8位。 由于前8位是您已解释过的一个值,因此这将提取编码为高位的内容。

例如:

如果你的两个参数是5(要编码到高部分)和4(要编码成低字):

低位字,二进制 00000100

更高的单词,二进制 00000101

合: 0000010100000100

如此按位&amp;用0xFF会给你4 将值向右移8位将为您提供5。

此外,这些很可能是无符号整数。有符号整数通常不用于此类工作。

答案 1 :(得分:1)

正如其他人所说,你应该把它重写为一个简洁的问题。 ..但是,这听起来像你要问的是:“这段代码在做什么”。我会试着解释一下。

你的case语句正在执行这一行:action.code = ACTION_LAYER_TAP_KEY((keycode >> 0x8) & 0xF, keycode & 0xFF);

ACTION_LAYER_TAP_KEY有2个参数。让我们分别看看它们。

第一个是(keycode >> 0x8) & 0xF,它的作用是取keycode并将它向右移8位(失去的位丢失)。然后使用0xF00001111)对结果进行加法(按位)。除了前4位之外,它具有丢弃所有内容的效果。

第二个是keycode & 0xFF。这样做会丢弃除键码的前8位以外的所有内容。所以现在参数是键码位8-11和键码位0-7。

好的,现在ACTION_LAYER_TAP_KEY对这些数据做了什么?

#define ACTION_LAYER_TAP_KEY(layer, key) ACTION_LAYER_TAP((layer), (key))

好的,它使用相同的参数调用ACTION_LAYER_TAP。现在让我们来看看。

ACTION_LAYER_TAP(layer, key) (ACT_LAYER_TAP<<12 | (layer)<<8 | (key))

首先需要ACT_LAYER_TAP,这可能是一个常数,并将其向左移位12。然后它对layer执行相同的操作,除了8,然后它需要这两个和key和/或它们(按位)。结果将<ACT_LAYER_TAP><layer><key>打包到整数中。图层的值可以是0-15,密钥的值可以是0-255。

回到上面的内容,我们可以看到<layer>实际上只是keycode的第8-11位。 key是keycode的0-7位。所以我们最终得到的是<ACT_LAYER_TAP><first 12 bits of keycode>打包成一个整数。