我有一个 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;
最佳答案
我建议您始终以网络字节顺序通过线路发送数字。这消除了以下问题:
- 为您的结构生成特定于编译器的字边界。
- 特定于您的硬件的字节顺序(发送和接收)。
此外,无论您在哪个平台上运行 Java,Java 的数字始终以网络字节顺序存储(JVM 规范需要特定的字节顺序)。
java.nio.ByteBuffer
是一个非常好的从流中提取位的类,它可以包装任意字节数组;不仅仅是来自 java.nio
中 I/O 类的那些。如果可能的话,你真的不应该手动编写你自己的原始值提取代码(即位移等),因为很容易出错,代码对于相同类型的每个实例都是相同的,并且有很多为您提供此功能的标准类。
例如:
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;
}
}
现在,要创建一个,只需调用 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);
在检索值之前。
关于java - 在 Java 中访问的 C 结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2151960/