所以在昨天的工作中,我不得不编写一个应用程序来计算AFP文件中的页面。所以我拂去了我的MO:DCA规范PDF并找到了结构化字段BPG (Begin Page)
及其3字节标识符。应用程序需要在AIX机器上运行,所以我决定用Java编写它。
为了获得最大效率,我决定读取每个结构化字段的前6个字节,然后跳过字段中的剩余字节。这会让我:
0: Start of field byte
1-2: 2-byte length of field
3-5: 3-byte sequence identifying the type of field
所以我检查字段类型并增加一个页面计数器,如果它是BPG
,如果不是,我就不会。然后我跳过字段中的剩余字节而不是通读它们。在这里,跳过(实际上是字段长度)是我发现Java使用带符号字节的地方。
我做了一些谷歌搜索,发现了很多有用的信息。当然,最有用的是执行按位&
到0xff
以获取unsigned int值的指令。这对我来说是必要的,以获得可用于计算要跳过的字节数的长度。
我现在知道,在128,我们从-128开始向后计数。我想知道的是按位运算在这里是如何工作的 - 更具体地说,我是如何得到负数的二进制表示。
如果我正确理解按位&
,则结果等于只设置两个数字的公共位的数字。所以假设byte b = -128
,我们会:
b & 0xff // 128
1000 0000-128
1111 1111 255
---------
1000 0000 128
那么我怎样才能到达1000 0000 -128?如何获得不太明显的二进制表示,如-72或-64?
答案 0 :(得分:18)
为了获得负数的二进制表示,你计算二的补码:
让我们以-72为例:
0100 1000 72
1011 0111 All bits inverted
1011 1000 Add one
因此-72的二进制(8位)表示为10111000
。
实际发生的情况如下:您的文件有一个值为10111000
的字节。当解释为无符号字节(可能是你想要的)时,这是88。
在Java中,当此字节用作int时(例如因为read()
返回int,或者因为隐式提升),它将被解释为带符号的字节,并符号扩展为{{ 1}}。这是一个值为-72的整数。
通过与11111111 11111111 11111111 10111000
进行AND运算,您只保留最低的8位,因此您的整数现在为0xff
,即88。
答案 1 :(得分:2)
我想知道的是按位运算在这里是如何工作的 - 更具体地说,我是如何得到负数的二进制表示。
负数的二进制表示是对应的正数进行比特翻转,并加1。此表示称为two's complement。
答案 2 :(得分:1)
我猜这里的神奇之处在于字节存储在一个更大的容器中,可能是一个32位的int。如果该字节被解释为有符号字节,则它将被扩展为表示32位int中的相同数字,即如果该字节的最高有效位(第一个)是1,那么在32位int中该1左边的位也变为1(这是由于负数表示的方式,两个补码)。
现在,如果你用& 0xFF
那个int切断了那些1并最终得到一个表示你读过的字节值的“正”int。
答案 3 :(得分:1)
不确定你真正想要的:)我假设你问的是如何提取有符号的多字节值?首先,看看签名扩展单个字节时会发生什么:
byte[] b = new byte[] { -128 };
int i = b[0];
System.out.println(i); // prints -128!
因此,符号正确地扩展到32位而不做任何特殊操作。字节1000 0000正确地扩展到1111 1111 1111 1111 1111 1111 1000 0000。 您已经知道如何通过与0xFF进行AND运算来抑制符号扩展 - 对于多字节值,您只希望将最高有效字节的符号扩展为extendet,并将您想要视为无符号的较低有效字节视为假设网络字节order,16位int值):
byte[] b = new byte[] { -128, 1 }; // 0x80, 0x01
int i = (b[0] << 8) | (b[1] & 0xFF);
System.out.println(i); // prints -32767!
System.out.println(Integer.toHexString(i)); // prints ffff8001
您需要禁止除最重要字节之外的每个字节的符号扩展,因此要将带符号的32位int提取为64位长:
byte[] b = new byte[] { -54, -2, -70, -66 }; // 0xca, 0xfe, 0xba, 0xbe
long l = ( b[0] << 24) |
((b[1] & 0xFF) << 16) |
((b[2] & 0xFF) << 8) |
((b[3] & 0xFF) );
System.out.println(l); // prints -889275714
System.out.println(Long.toHexString(l)); // prints ffffffffcafebabe
注意:在基于intel的系统上,字节通常以相反的顺序存储(最低有效字节优先),因为x86架构按此顺序在内存中存储较大的实体。许多x86原创软件也以文件格式使用它。
答案 4 :(得分:0)
要获得无符号字节值,您可以。
int u = b & 0xFF;
或
int u = b < 0 ? b + 256 : b;
答案 5 :(得分:0)
对于设置了第7位的字节:
unsigned_value = signed_value + 256
使用字节计算数学时,计算模256.有符号和无符号之间的区别在于您为等价类选择不同的代表,而作为位模式的基础表示对于每个等价类保持相同。这也解释了为什么加法,减法和乘法与位模式具有相同的结果,无论您是使用有符号还是无符号整数进行计算。