用Java访问的AC结构

int*_*iha 4 c java struct cross-platform

我有一个C结构,通过一些中间网络发送,并通过Java代码通过串行链接接收.Java代码给了我一个字节数组,我现在想把它重新打包为原始结构.现在,如果接收代码在C中,这很简单.有没有简单的方法将java中的byte []重新打包为C结构.我在java方面的经验很少,但这似乎不是常见的问题,或者在我能找到的任何常见问题解答中都解决了.

仅供参考,C结构是

struct data {
     uint8_t        moteID;
    uint8_t     status; //block or not
    uint16_t   tc_1;
    uint16_t   tc_2;
    uint16_t   panelTemp;  //board temp
    uint16_t   epoch#;
    uint16_t   count;    //pkt seq since the start of epoch
    uint16_t   TEG_v;   
    int16_t   TEG_c;    
 }data;
Run Code Online (Sandbox Code Playgroud)

Kev*_*ock 8

我建议您始终以网络字节顺序在线路上发送数字.这消除了以下问题:

  1. 编译器特定的单词边界生成为您的结构.
  2. 特定于您的硬件的字节顺序(发送和接收).

此外,无论您运行Java的平台(JVM规范需要特定的字节顺序),Java的数字始终以网络字节顺序存储.

从流中提取位的一个非常好的类是java.nio.ByteBuffer,它可以包装任意字节数组; 不只是来自I/O类的那些java.nio.如果可能的话,你真的不应该手动编码自己的原始值提取(即位移等等)因为很容易弄错,代码对于同一类型的每个实例都是相同的,并且有很多标准类为您提供此类.

例如:

public class Data {

    private byte moteId;
    private byte status;
    private short tc_1;
    private short tc_2;
    //...etc...
    private int tc_2_as_int;

    private Data() {
        // empty
    }

    public static Data createFromBytes(byte[] bytes) throws IOException {
        final Data data = new Data();
        final ByteBuffer buf = ByteBuffer.wrap(bytes);

        // If needed...
        //buf.order(ByteOrder.LITTLE_ENDIAN);

        data.moteId = buf.get();
        data.status = buf.get();
        data.tc_1 = buf.getShort();
        data.tc_2 = buf.getShort();
        // ...extract other fields here

        // Example to convert unsigned short to a positive int
        data.tc_2_as_int = buf.getShort() & 0xffff;

        return data;        
    }

}
Run Code Online (Sandbox Code Playgroud)

现在,要创建一个,只需打电话Data.createFromBytes(byteArray).

请注意,Java没有无符号整数变量,但这些变量将使用完全相同的位模式进行检索.因此,未设置高位的任何内容在使用时都将完全相同.如果您希望使用无符号数字,则需要处理高位.有时这意味着将值存储在下一个更大的整数类型中(byte - > short; short - > int; int - > long).

编辑:更新了示例,以显示如何使用无符号值将short(16位带符号)转换为int(32位带符号)tc_2_as_int.

另请注意,如果您无法更改字节顺序且它不是网络顺序,那么在检索值之前,java.nio.ByteBuffer仍然可以在此处为您提供服务buf.order(ByteOrder.LITTLE_ENDIAN);.