欢迎使用CSDN-markdown编辑器

来源:互联网 发布:淘宝流量充值如何退款 编辑:程序博客网 时间:2024/05/17 22:03

Java解析C语言那些事

本本人从事Android开发工作,最近由于工作需要,需要与C++语言服务器进行TCP交互。在java中Socket编程已经为我们封装了很多好用的Api,今天我们讨论的是和C++交互过程中的一些心得。首先要明确几个概念

  • 什么是内存对齐
  • 为什么要内存对齐

-内存对齐:

内存对齐,或者说字节对齐,是一个数据类型所能存放的内存地址的属性(Alignment is a property of a memory address)。
这个属性是一个无符号整数,并且这个整数必须是2的N次方(1、2、4、8、……、1024、……)。
当我们说,一个数据类型的内存对齐为8时,意思就是指这个数据类型所定义出来的所有变量,其内存地址都是8的倍数。

当一个基本数据类型(fundamental types)的对齐属性,和这个数据类型的大小相等时,这种对齐方式称作自然对齐(naturally aligned)。
比如,一个4字节大小的int型数据,默认情况下它的字节对齐也是4。
-为什么要内存对齐:

这是因为,并不是每一个硬件平台都能够随便访问任意位置的内存的。我个人的理解可能在不同的平台上面内存的分配情况是不一样的。这个也是导致java中没有结构体这个数据结构的原因。
我们都知道,在结构体内部可能有多个基本类型,那么子阿布同平台他所占的内存大小也是不一样的的使用。那么问题来了,java中如何实现C或C++中的结构体类型。

-Javolution
这是一个第三方资源库。 [ Javolution ]

javolution的使用:

1 javolution支持maven方式引入

<dependency>          <groupId>org.javolution</groupId>          <artifactId>javolution-core-java</artifactId>          <version>6.0.0</version>      </dependency>

2 可以下载相应的Jar加入到你的工程中。(注意:我开始下载的是5.X版本,有些问题。下载6.x就好了)。

开始使用Javolution:
在java中若要定义结构体形式的数据结构。你的类首先应该继承Javolution的Struct类。而且java中的基本类型也不能直接使用。要使用Struct类中的基本类型,如下:

    public final  Signed32 version = new Signed32();                            public final  Signed32 eMainType = new Signed32();                      public final  Bool hasSubtype = new Bool();                  public final  Signed32 nLen = new Signed32();                           public final   UTF8String  HeadEnding = new UTF8String(2);              public final  Signed32 eSubType = new Signed32();                   

值得注意的是:在你自己定义的“结构体”中,ByteOrder方法返回的小端对齐的。

另外在附加两个工具方法。分别是Struct转成byte[]和byte[]转成Struct:

    /**         * 把类型转化成byte数组              * @param struct 实体类型         * @return         */        public static byte[] GetBytesFromStruct( javolution.io.Struct struct)        {            int sz = struct.size();            ByteBuffer bb = struct.getByteBuffer();            if( bb == null)return null;            byte[] buffer = new byte[sz];            bb.position(0);     // 设置位置            bb.get(buffer);//          System.out.println(bb);            return buffer;        }
/**         * 把byte数组转换成类型         *          * @param struct 实体类型         * @param bytes  原始数据流         * @param offset   开始位置         * @param length   取长度         * @return         */        public static Struct GetStructFromByte(Struct struct, byte[] bytes,int offset,int length)        {            ByteBuffer bb = ByteBuffer.wrap(bytes, offset, length);              bb.position(0);            bb.order(ByteOrder.LITTLE_ENDIAN);            struct.setByteBuffer(bb, 0);            return struct;        }
 值得注意的是:    1 关于如何为结构体赋值或是获取其中某个属性的值可以通过Struct.XXX.set()和   Struct.XXX.get()方法实现。    2 在你自己定义的结构体中,每个参数的顺序要按照协议约定的顺序,否则返回的结构将不是你期待的结果。    3 获取你自己定义的结构的内存大小使用的Struct.Size()方法。

网上有对这种方式的问题做出了总结,目前本人还没有遇到:
一 对齐方式改变了:结构体在遇到64位的数据类型的时候,就自动把前面的数据按8字节对齐了,这样子的话coin数据本应该是由数据流的第12字节的位置开始解析变成了第16个字节开始解析,后面的数据就必然会跟着移位
二 在C中char content[0]content数据存储的是可变数据的开始地址,在c的结构体里是不占用大小的,所以这个结构体的大小应该为2.在java里就定义不出来的

详细问题与解决方式的请参考。 [ Javolution的坑 ]

以上就是在这次工作中的一点心得,另外网上还有一种实现方式是通过JNI来实现的。个人还没有尝试。

0 0
原创粉丝点击