1

我正在尝试编写代码,让我将 CAN 消息的数据字段的值打印为一系列十六进制形式的短裤。CAN 消息数据字段包含 4 个 short,例如,我可能会打印出一条消息为“FFFF EEEE ABAB 2013”​​。

我可以将 CAN 消息的 2 个短片编码为一个整数值,只要未设置整数的第 32 位,一切都可以正常工作。因为 Java 使用有符号整数,所以设置第 32 位会导致它打印出一系列“f”。我想要的是整数充当无符号值,以便将其打印出来不会引起问题。

这是一个出错的例子:

(int value): 0x80000000
(string rep short 1): 0xffff8000
<crash>

以下是它在其他情况下的工作方式:

(int value): 0x40000000
(string rep short 1): 0x4000
(string rep short 2): 0x0

我尝试表示 CAN 消息数据以及发生崩溃的代码:

public String getFormattedData() {
    String dataString = "";

    for(String aShort : Utility.splitStringByWhitespace(getData())) {
        try{
            dataString += ("0000".substring(0, 4 - aShort.length()) + aShort) + " ";
        } catch(Exception e) {
            System.out.println(getData());
            System.exit(1);
        }
    }

    return dataString.toUpperCase();
}

具体来说,崩溃的发生是因为“f”s 将 short 的字符串表示的长度增加到 8 个字符,因此“4 - aShort.length()”将产生一个负值,这是无效的。

编辑:对于那些询问的人,在这种特殊情况下,这就是我在将数据转换为字符串表示之前使用整数对数据进行编码的方式:

public String convertToCANMessageData(PWMChannel channel) {
    int channelVal = channel.getValue();
    int entryDataHI = 0, entryDataLO = 0;

    entryDataHI += channelVal << 24;
    entryDataHI += smallData << 8;
    entryDataHI += (largeData >> 8) & 0xFF;
    entryDataLO += (largeData & 0xFF) << 24;

    if(ramping) {
        entryDataHI = entryDataHI | (1 << 16);
    } else {
        entryDataHI = entryDataHI & ~(1 << 16);
    }

    if(jumping) {
        entryDataHI = entryDataHI | (1 << 17);
    } else {
        entryDataHI = entryDataHI & ~(1 << 17);
    }

    if(frequencySetting) {
        entryDataHI = entryDataHI | (1 << 18);
    } else {
        entryDataHI = entryDataHI & ~(1 << 18);
    }

    return String.format("%x %x %x %x", entryDataHI >> 16, entryDataHI & 0xFFFF,
                            entryDataLO >> 16, entryDataLO & 0xFFFF);
}
4

3 回答 3

2

要回答标题中的问题,要设置 an 的第 32 位,int您可以使用按位 OR 运算符:

myInteger |= (1 << 31);

如果您不希望这“弄乱”字符串表示,那就是如何将整数转换为字符串的问题。例如,该Integer.toHexString方法将整数视为无符号:

print(Integer.toHexString(-3)); // output: fffffffd

更新:格式化数字时使用无符号左移>>>:常规左移>>扩展符号位,因此负数的左移保持负数并且不会“突然”变成一个巨大的正数。

return String.format("%x %x %x %x", entryDataHI >>> 16, entryDataHI & 0xFFFF,
                        entryDataLO >>> 16, entryDataLO & 0xFFFF);

或者,您可以使用您似乎已经熟悉的掩蔽:

return String.format("%x %x %x %x", (entryDataHI >> 16) & 0xFFFF, entryDataHI & 0xFFFF,
                        (entryDataLO >> 16) & 0xFFFF, entryDataLO & 0xFFFF);
于 2013-09-19T14:20:36.363 回答
1

只需使用无符号位移来获取整数的上半部分。

int i = 0x80000000;
short s = (short)(i >>> 16);
s is 0x8000
于 2013-09-19T14:20:35.997 回答
0

我现在通过添加一个实用函数解决了这个问题:

public static int parseShort(String aShort) {
    if(aShort.length() > 4) aShort = aShort.substring(aShort.length()-4);

    return Integer.parseInt(aShort, 16);
}

如果有人有更好的解决方案,我很乐意将他们的答案标记为已接受并尝试一下。

于 2013-09-19T14:09:06.210 回答