Java Bitshift错误,为负数

Java Bitshift error with negatives?

本文关键字:Bitshift 错误 Java      更新时间:2023-10-16

http://www.fastcgi.com/devkit/doc/fcgi-spec.html第3.4节:

 typedef struct {
        unsigned char nameLengthB0;  /* nameLengthB0  >> 7 == 0 */
        unsigned char valueLengthB0; /* valueLengthB0 >> 7 == 0 */
        unsigned char nameData[nameLength];
        unsigned char valueData[valueLength];
    } FCGI_NameValuePair11;
    typedef struct {
        unsigned char nameLengthB0;  /* nameLengthB0  >> 7 == 0 */
        unsigned char valueLengthB3; /* valueLengthB3 >> 7 == 1 */
        unsigned char valueLengthB2;
        unsigned char valueLengthB1;
        unsigned char valueLengthB0;
        unsigned char nameData[nameLength];
        unsigned char valueData[valueLength
                ((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0];
    } FCGI_NameValuePair14;
    typedef struct {
        unsigned char nameLengthB3;  /* nameLengthB3  >> 7 == 1 */
        unsigned char nameLengthB2;
        unsigned char nameLengthB1;
        unsigned char nameLengthB0;
        unsigned char valueLengthB0; /* valueLengthB0 >> 7 == 0 */
        unsigned char nameData[nameLength
                ((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0];
        unsigned char valueData[valueLength];
    } FCGI_NameValuePair41;
    typedef struct {
        unsigned char nameLengthB3;  /* nameLengthB3  >> 7 == 1 */
        unsigned char nameLengthB2;
        unsigned char nameLengthB1;
        unsigned char nameLengthB0;
        unsigned char valueLengthB3; /* valueLengthB3 >> 7 == 1 */
        unsigned char valueLengthB2;
        unsigned char valueLengthB1;
        unsigned char valueLengthB0;
        unsigned char nameData[nameLength
                ((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0];
        unsigned char valueData[valueLength
                ((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0];
    } FCGI_NameValuePair44;

我正在Java中实现这一点,为了完成valueLengthB3 >> 7 == 1等部分,我只是将其设置为负数。这行不通。否定在Java中是如何工作的,在Java中如何执行此操作?

我当前的代码:

public void param(String name, String value) throws IOException {
    if (fp) {
        throw new IOException("Params are already finished!");
    }
    if (name.length() < 128) {
        dpout.write(name.length());
    }else {
        dpout.writeInt(-name.length());
    }
    if (value.length() < 128) {
        dpout.write(value.length());
    }else {
        dpout.writeInt(-value.length());
    }
    dpout.write(name.getBytes());
    dpout.write(value.getBytes());
}

Java使用非常常规的整数运算。与C和C++相关的两个主要特性是

  1. Java除了char(16位宽)之外没有其他无符号整数类型,并且
  2. Java有单独的算术(>>)和逻辑(>>>)右移运算符。前者通过用左操作数最高有效位的副本填充结果所需的最高有效位来保留符号,而后者用零填充结果的最高有效位数

Java的优点是,所有基元类型在所有平台上都具有众所周知的、一致的大小和签名性,并且它的两个右移运算符对所有有效操作数都具有定义良好的语义。相反,在C中,对负值执行右移的结果是实现定义的,所有的标准数据类型都具有实现定义的大小,并且一些类型(char)具有实现定义签名性。

然而,既然您已经发布了一些代码,那么这些似乎都不是您的问题。我不明白为什么你认为否定一个数字会进行任何形式的转换,或者实际上,为什么你认为你想要做的事情需要转换。

特别要注意的是,Java使用2的补码整数表示法(这也是C编译器最常见的选择),因此否定一个数字所修改的不仅仅是符号位。如果你只想设置int的符号位,那么你可以拼写

value.length() | 0x80000000

如果您通过导线接收byte,它们将被签名,这意味着最高有效位将是符号位。如果你想从byte中提取符号位,你会想到两种合理的方法:通过与0进行比较来测试负性,或者使用>>>运算符,而不是>>运算符。

下面的代码显示了我如何在C中取消对signed chars的数组的序列化。我无法想象为什么这在Java中不起作用,假设databytes的数组……尽管我确信这会很可怕。

long offset = 0;
long nameLength  = data[offset] >= 0 ? data[offset++] : (-(long)data[offset++] << 24)
                                                      + ( (long)data[offset++] << 16)
                                                      + ( (long)data[offset++] <<  8)
                                                      +         data[offset++];
long valueLength = data[offset] >= 0 ? data[offset++] : (-(long)data[offset++] << 24)
                                                      + ( (long)data[offset++] << 16)
                                                      + ( (long)data[offset++] <<  8)
                                                      +         data[offset++];
for (long x = 0; x < nameLength; x++) {
    /* XXX: Copy data[offset++] into name */
}
for (long x = 0; x < valueLength; x++) {
    /* XXX: Copy data[offset++] into value */
}