Java Bitshift 错误与否定?

Posted

技术标签:

【中文标题】Java Bitshift 错误与否定?【英文标题】:Java Bitshift error with negatives? 【发布时间】:2015-03-30 21:39:49 【问题描述】:

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 &gt;&gt; 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());

【问题讨论】:

struct 并不是为了指定网络上的表示。我不知道 Java,但它肯定有比这更好的序列化/反序列化机制。 “这不起作用”不是描述性的,尽管它并不让我感到惊讶。您的问题被误导,模糊且缺乏大量研究。需要我的建议吗?告诉我们这是试图解决哪个实际问题,并询问如何在 Java 中做到这一点......然后你可能会得到一个很好的答案。 这不是关于结构,而是关于valueLengthB3 &gt;&gt; 7 == 1,你如何在Java 内部以4 字节的方式评估它?它基本上是代码转换。我正在尝试在 Java 中为 FCGI 协议实现可变大小长度。 @undefinedbehaviour @pbacdefp 我不明白你在问什么。 如果您提供您正在编写的代码的相关部分,并解释您实际看到的不需要的结果,将会有所帮助。由于您发布的代码既不是有效的 C 也不是有效的 C++,因此无法提供太多指导。 既然您问的是Java,那么您的问题与C 或C++ 有什么关系?也许您应该包括其他使用位移的语言或删除 C 和 C++ 标记。 【参考方案1】:

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

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

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

现在您已经发布了一些代码,但是,看起来这些实际上都不是您的问题。我不明白为什么你认为否定一个数字会执行任何类型的转换,或者实际上,为什么你认为你想要做的事情完全需要转换。

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

value.length() | 0x80000000

【讨论】:

谢谢!我只是不明白 Java 签名是如何工作的。我以为它做了你刚才给我看的。谢谢! 否定位和翻转位并不完全相同。 ~x = -1-x. @user3618509 阅读此内容docs.oracle.com/javase/tutorial/java/nutsandbolts/… How are integers internally represented at a bit level in Java? en.wikipedia.org/wiki/Two%27s_complement 谢谢@LouisWasserman,我不知道我在写这篇文章时在想什么。已更正。【参考方案2】:

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

以下代码显示了我如何在 C 中反序列化这样一个 signed chars 数组。我无法想象为什么这在 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 */

【讨论】:

以上是关于Java Bitshift 错误与否定?的主要内容,如果未能解决你的问题,请参考以下文章

如何否定Java中的任何正则表达式

否定中医者多犯这个根本错误

带有`\R`的Java-8 正则表达式否定回溯

java 在Java中修复否定模数 - http://stackoverflow.com/a/18994115

用于查找 HTML 标签及其内容的正则表达式的否定 - java

生长的法则-哲学与结构