在 Java 中表示 C 左移 signed char 与 unsigned char

Representing C shift left signed char vs. unsigned char in Java

我正在尝试将一些 C 代码移植到 Java 中,并且一直在努力解释转换顺序、运算符优先级,并确保结果符合我的预期。我已经阅读了很多帖子并认为我已经弄明白了,但我想确保我已经正确地表达了它。

我要移植的 original C code 是这样的:

UInt32 _strtoul(char *str, int size, int base)
{
    UInt32 total = 0;
    int i;

    for (i = 0; i < size; i++)
    {
        if (base == 16)
            total += str[i] << (size - 1 - i) * 8;
        else
           total += ((unsigned char) (str[i]) << (size - 1 - i) * 8);
    }
    return total;
}

在代码中,将一个 4 字节的值(字节数组或字符串)转换为 32 位整数。我试图理解条件句中两个子句的区别;具体来说,(unsigned char)演员表的实际效果是什么。

据我了解,在 C 中,字节在左移之前被提升为 int。但是,我不明白它是如何转化为 C 中的按位表示的。在顶部分支(base == 16,有符号)中提升字节值 0xff (-1) 是否正确从 0xff 到 0xffffffff 而在底部分支(无符号)中,值 0xff (255) 将从 0xff 提升到 0x000000ff?

鉴于此解释,以下 Java 代码是否是忠实的表示(Uint 与 int return 类型除外)?

public static int strtoul(byte[] bytes, int size, int base) {
    int total = 0;
    for (int i = 0; i < size; i++) {
        if (base == 16) {
            // signed bytes, shifted
            total += bytes[i] << (size - 1 - i) * 8;
        } else {
            // unsigned bytes, shifted
            total += bytes[i] & 0xff << (size - 1 - i) * 8;
        }
    }
    return total;
}

我没有使用 sscanf,因为您正在明确寻找 uint32 解决方案。如果你真的不在乎,它就像

一样简单
#include <stdio.h>

unsigned int _strtoui(char *s)
{
    unsigned int ret;
    sscanf(str, "%u", &ret); /* use "%x" for hexadecimal */
    return ret;
}

我想 Java 中有类似 sscanf 的东西。无论如何,这是我对 uint32_t/UInt32 的解决方案。当心输入数据中的溢出。此外,如果字符不是(十六进制)数字,这些函数将给出废话。改进它是另一项练习。

#include <stdint.h>

uint32_t _strtoui32(char *str)
{
    int i;
    uint32_t total = 0;

    for(i=0; str[i] != '[=11=]'; i++)
        total = total*10 + str[i] - '0';

    return total;
}

uint32_t _hextoui32(char *str)
{
    int i;
    uint32_t total = 0;

    for(i=0; str[i] != '[=11=]'; i++) {
        total *= 16;
        if(str[i] > 47 && str[i] < 58) /* base 10 number */
            total += str[i] - '0';
        else if(str[i] > 64 && str[i] < 71) /* uppercase A-F */
            total += str[i] - 'A' + 10;
        else /* lowercase a-f */
            total += str[i] - 'a' + 10;
    }

    return total;
}

uint32_t _hstrtoui32(char *str, int base)
{
    if(base == 16)
        return _hextoui32(str);
    else
        return _strtoui32(str);
}

根据 Java's operator precedence,您需要在 bytes[i] & 0xff 周围加上括号,否则它会被解析为 bytes[i] & (0xff << (size - 1 - i) * 8).

所以最后你的代码应该是这样的:

public static int strtoul(byte[] bytes, int size, int base) {
    int total = 0;
    for (int i = 0; i < size; i++) {
        if (base == 16) {
            // signed bytes, shifted
            total += bytes[i] << (size - 1 - i) * 8;
        } else {
            // unsigned bytes, shifted
            total += (bytes[i] & 0xff) << (size - 1 - i) * 8;
        }
    }
    return total;
}