Java 负数移位错误?

Java Bitshift error with negatives?

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. 之外没有无符号整数类型
  3. Java 具有单独的算术 (>>) 和逻辑 (>>>) 右移运算符。前者通过用左操作数的最高有效位的副本填充结果的所需最高有效位来保留符号,而后者用零填充结果的最高有效位。

Java 的优点是所有原始类型在所有平台上都具有众所周知的、一致的大小和符号,并且它的两个右移运算符对所有有效操作数都有明确定义的语义。相比之下,在 C 中,对负值执行右移的结果是实现定义的,all 标准数据类型具有实现定义的大小,并且某些类型(char) 具有实现定义的符号。

现在您已经发布了一些代码,但是,似乎 none 实际上是您的问题。我不明白为什么您认为取负数会执行任何类型的移位,或者实际上,为什么您认为对于您要尝试做的事情根本需要移位。

请特别注意 Java 使用二进制补码整数表示(这也是迄今为止 C 编译器最常见​​的选择),因此对数字取反不仅仅修改符号位。相反,如果您只想设置 int 的符号位,那么您可以拼写

value.length() | 0x80000000

如果您通过网络接收 byte,它们将被签名,这意味着最高有效位将是符号位。如果您想从 byte 中提取符号位,可以想到两种明智的方法:通过与 0 进行比较来测试否定性或使用 >>> 运算符,而不是 >> 运算符.

下面的代码显示了我如何在 C 中反序列化这样一个 signed char 数组。我无法想象为什么这在 Java 中不起作用,假设 data 而是 bytes 的数组...虽然我确定它会非常可怕。

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 */
}