C语言数据位扩展
2025-10-25
2
0
在分析HID报告描述符代码部分时,看到一个很有意思的函数:
VOID
HidParser_SignRange(
IN ULONG Minimum,
IN ULONG Maximum,
OUT PULONG NewMinimum,
OUT PULONG NewMaximum)
{
ULONG Mask = 0x80000000;
ULONG Index;
for (Index = 0; Index < 4; Index++)
{
if (Minimum & Mask)
{
Minimum |= Mask;
if (Maximum & Mask)
Maximum |= Mask;
break;
}
Mask >>= 8;
Mask |= 0xff000000;
}
*NewMinimum = Minimum;
*NewMaximum = Maximum;
}
这个函数的功能是对有符号数值范围进行符号扩展处理。
函数参数说明:
Minimum:输入的最小值Maximum:输入的最大值NewMinimum:输出的处理后的最小值NewMaximum:输出的处理后的最大值
算法逻辑:
检测符号位:从最高位开始,每8位(一个字节)检测一次符号位
- 初始掩码
Mask = 0x80000000(最高位为1,其余为0) - 循环4次,分别检测每个字节的最高位
- 初始掩码
符号扩展处理:
- 如果发现某个字节的最高位为1(表示负数),则对该数值进行符号扩展
Minimum |= Mask将最小值从该字节开始向上进行符号扩展- 如果最大值在该位置也是1,同样对最大值进行符号扩展
提前返回:
- 一旦检测到需要符号扩展的情况,对数据进行位扩展,扩展之后跳出循环,设置新值,并返回
无符号情况:
- 如果4次循环都没有检测到符号位,说明是正数范围,直接复制到输出参数
应用场景:
这个函数主要用于处理HID(人机接口设备)协议中的数据范围,确保有符号数值在32位系统中能够正确地进行符号扩展,保持数值的符号语义不变。
以上是DEEP SEEK给出的解释,实际本人刚拿到这段代码时,是一个有BUG的函数,原函数中是return,而是break,经过本人的火眼金睛给找出来了。
以上函数的使用场景是因为在HID报告描述符进行数据解析时,统一使用的是ULONG来进行的,这样导致一个有符号的数据如CHAR,SHORT等,当出现负值时,不会进行自动进行位扩展的,所以需要这个函数来实现。
在HID报告描述符中,该函数的触发条件是:Minimum>Minimum
ULONG LogicalMinimum = GlobalItemState->LogicalMinimum;
ULONG LogicalMaximum = GlobalItemState->LogicialMaximum;
if (LogicalMinimum > LogicalMaximum)
{
HidParser_SignRange(LogicalMinimum, LogicalMaximum, &LogicalMinimum, &LogicalMaximum);
}
而在上面数据的赋值时,使用的是
typedef struct
{
ITEM_PREFIX Prefix;
union
{
UCHAR UData8[4];
CHAR SData8[4];
USHORT UData16[2];
SHORT SData16[2];
ULONG UData32;
LONG SData32;
}Data;
}SHORT_ITEM, *PSHORT_ITEM;
代码如下:
ULONG Data;
if (CurrentItemSize == 1)
Data = CurrentShortItem->Data.UData8[0];
else if (CurrentItemSize == 2)
Data = CurrentShortItem->Data.UData16[0];
else if (CurrentItemSize == 4)
Data = CurrentShortItem->Data.UData32;
可见,最主要的原因是无论是有符号还是无符号,都统一使用了UNSIGNED LONG来处理了,这时编译器不会自动进行位扩展。因为只有编译器检测到有符号到无符号的转换时,才会进行位扩展。
所以,HidParser_SignRange函数是为了弥补上述代码编写的BUG.
当然,我们也可以用下面的代码进行测试验证:
#include <iostream>
#include <Windows.h>
#include <tchar.h>
#define IN
#define OUT
VOID
HidParser_SignRange(
IN ULONG Minimum,
IN ULONG Maximum,
OUT PULONG NewMinimum,
OUT PULONG NewMaximum)
{
ULONG Mask = 0x80000000;
ULONG Index;
for (Index = 0; Index < 4; Index++)
{
if (Minimum & Mask)
{
Minimum |= Mask;
if (Maximum & Mask)
Maximum |= Mask;
break;
}
Mask >>= 8;
Mask |= 0xff000000;
}
*NewMinimum = Minimum;
*NewMaximum = Maximum;
}
int main()
{
UCHAR min = -100;
UCHAR max = 50;
ULONG Minimum = min;//不会进行位扩展
ULONG Maximum = max;
CHAR Testmin = -100;
ULONG TestMin = Testmin;//自动位扩展
ULONG NewMinimum;
ULONG NewMaximum;
HidParser_SignRange(Minimum, Maximum, &NewMinimum, &NewMaximum);
printf("min = 0x%02x\n", min);
printf("max = 0x%02x\n", max);
printf("Testmin = 0x%02x\n", Testmin);//%02x也限制不了%x扩展到32位
printf("TestMin = 0x%x\n", TestMin);
printf("NewMinimum = 0x%x\n", NewMinimum);
printf("NewMaximum = 0x%x\n", NewMaximum);
return 0;
}
C++高级教程





