大端法和小端法(1)
Monday, September 24, 2007
如果文件中存储的一段数据为 ----------- 10001010 10100100 -------------(以大端法表示的数据)
如何拼接成Java的int类型,如何拼接成C++的int类型。
现在假设内存上的
(736424) 10001010 //低地址736424
(736425) 10100100 //高地址736425
现在知道这两块内存存放的是用大端法表示的无符号整数!(大端法――低地址存放高位, X86平台存放文件小端法),
分别用C++和Java求解上面的整数?
//例a (java) class Test { public static void main(String[] args) { //(736424) 10001010 //(736425) 10100100 高位在前的无符号整型 byte[] buf = new byte[2]; buf [0] = (byte)0x8A;//低地址存放高位 buf [1] = (byte)0xA4;//高地址存放低位 int result = (( buf[0] < 0 ? 256 + buf[0] : buf[0] ) << 8 ) | (buf[1] < 0 ? 256 + buf[1] : buf[1]); System.out.println(result); System.out.println(Integer.toBinaryString(result)); } } //snail:因为byte是有符号数,如果最高位是1,在进行移位操作时前会自动提到int(也可能是移好位再提升的,没有验证),在符号位前的所有24位会填充1,这样就会导致问题,要避免这个问题,可以像上面程序buf[0] < 0 ? 256 + buf[0] : buf[0]这样处理。只要执行下面三行,就知道是如何填充的了。 byte data = (byte)0x8F; System.out.println(data); System.out.println((int)data); 上面buf[0] < 0 ? 256 + buf[0] : buf[0]的意思将buf展开成整型的时候可以忽略符号位的影响。 下面 C++就没有这个麻烦,只要把映射2个地址的时候用unsigned char映射就行了,就不会认为最高位为符号位,在进行类型提升的时候也不会自动填充符号位1,见例b. |
//例b (C++) #include <iostream>
using namespace std;
int main(int argc,int argv[]){ //10001010 10100100 高位在前的无符号整型 unsigned char buf[2]; buf[0] = (char)0x8A; buf[1] = (char)0xA4; int result = buf[0] << 8 | buf[1]; cout << result << endl; return 0; } |
上面这个问题的讨论不涉及到位顺序,只涉及到字节顺序,实际上大端法和小端法表示的文件在位顺序是不是相反的呢?
(我原本一直以为是相反,而且从程序的种种迹象也表明是相反,但其实没有相反)
C++基本知识: C++的一个char类型几乎都包含8个二进制位,因此它可以保存256种不同的值。
与char不同的是,普通的int总是有符号的.(说明默认的char不一定总是有符号的)
一个char是有符号的还是没符号的? 不幸的是,关于普通char如何选择的问题是由实现决定的。
char c = 255; //255是”全1”, 十六进制的0xFF int i = c; cout << c << endl; // c 等于 -1; 在windows平台 x86环境,g++ v3.8编译器编译下 默认的char类型是有符号的! |
下面引用其他网上的两篇文章,对理解字节序的问题可能有帮助。
|
网络字节顺序、大端法、小端法引用自 http://blog.csdn.net/dodorunning/archive/2006/03/23/636605.aspx在国内的4种短信协议的协议头部分,都定义了4个字节长度的message length字段,字段的数据类型为无符号整形(也就是说,这个字段的范围是0-2^16-1);而在java语言中,没有无符号整形这种数据类型(如果用int类型来表示,由于java中int型是有符号数,则会发送溢出),我设想将message length存入long类型中,将数字的大小控制在0-2^16-1范围之内,当超过此范围归零重新开始。在网络传输时,将long类型先转化为byte数组,步骤如下:long l; byte[] b; b[0]=(byte)(l>>>24); b[1]]=(byte)(l>>>16); b[2]]=(byte)(l>>>8); b[3]]=(byte)(l); 此时,b[]中就按照网络字节顺序(大端法,即l的高位数据存放在byte[]的低位地址,因为地址是 从低向高发展的)存放着4个bytes的数据 使用OutputStream的public void write(byte[] b,int off,int len)方法来向Socket写字节流 ,写byte[0]至byte[3]的字节。
java.io |