欢迎使用CSDN-markdown编辑器

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值