我在理解此代码时遇到问题。我知道的是,我们已经将代码传递给了一个汇编程序,该汇编程序已将代码转换为“字节码”。现在,我有一个虚拟机,应该读取此代码。该功能应该读取第一个字节代码指令。我不明白这段代码中发生了什么。我想我们正在尝试读取此字节码,但不了解它是如何完成的。
static int32_t bytecode_to_int32(const uint8_t *bytecode, size_t size)
{
int32_t result;
t_bool sign;
int i;
result = 0;
sign = (t_bool)(bytecode[0] & 0x80);
i = 0;
while (size)
{
if (sign)
result += ((bytecode[size - 1] ^ 0xFF) << (i++ * 8));
else
result += bytecode[size - 1] << (i++ * 8);
size--;
}
if (sign)
result = ~(result);
return (result);
}
最佳答案
这段代码写得不好,在一行上执行了很多操作,因此包含各种潜在的错误。看起来很脆。bytecode[0] & 0x80
只需读取MSB符号位(假定它是2的补码或类似值),然后将其转换为布尔值即可。
循环从最高有效字节向后迭代到最低有效字节。
如果符号为负,则代码将对数据字节与0xFF进行XOR。基本上反转数据中的所有位。 XOR的结果为int
。
然后将数据字节(或以上XOR的结果)向左移i * 8
位。数据总是隐式提升为int
,因此,如果i * 8
碰巧得到的结果大于INT_MAX
,则这里有一个严重的未定义行为错误。在转换前强制转换为uint32_t
,执行转换,然后在转换后转换为带符号类型,这将是更安全的做法。
生成的int
转换为int32_t
-根据系统的不同,它们可以是相同类型或不同类型。
i增加1,大小减少1。
如果符号为负,则int32_t
会被反转为2的补码负数,该数字会被符号扩展,并且所有数据位将再次反转。除了随着左移而移入的所有零之外,这些零也被替换为1。如果这不是故意的,我不能告诉。因此,举例来说,如果您开始使用类似0x0081
的内容,那么现在可以使用类似0xFFFF01FF
的内容。我不知道这种格式如何有意义。
我认为bytecode[size - 1] ^ 0xFF
(等效于~
)是用来切换数据位的,以便以后调用~
时它们可以切换回其原始值。程序员必须用注释来记录这些技巧,如果这些技巧几乎可以胜任的话。
无论如何,不要使用此代码。如果只打算交换4字节整数的字节顺序(字节顺序),则必须从头开始重写此代码。
正确地做到了:
static int32_t big32_to_little32 (const uint8_t* bytes)
{
uint32_t result = (uint32_t)bytes[0] << 24 |
(uint32_t)bytes[1] << 16 |
(uint32_t)bytes[2] << 8 |
(uint32_t)bytes[3] << 0 ;
return (int32_t)result;
}
比上面更复杂的是高度可疑的代码。我们不必担心符号是一种特殊情况,上面的代码保留了原始的符号格式。
关于c - 用C语言进行按位运算(0x80,0xFF,<<),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/60092227/