我在理解此代码时遇到问题。我知道的是,我们已经将代码传递给了一个汇编程序,该汇编程序已将代码转换为“字节码”。现在,我有一个虚拟机,应该读取此代码。该功能应该读取第一个字节代码指令。我不明白这段代码中发生了什么。我想我们正在尝试读取此字节码,但不了解它是如何完成的。

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/

10-11 21:16