A C structure accessed in Java
c, cross-platform, java, struct
Solution
I would recommend that you send the numbers across the wire in network byte order all the time. This eliminates the problems of:
- Compiler specific word boundary generation for your structure.
- Byte order specific to your hardware (both sending and receiving).
Also, Java's numbers are always stored in network-byte-order no matter the platform that you run Java upon (the JVM spec requires a specific byte order).
A very good class for extracting bits from a stream is `java.nio.ByteBuffer`, which can wrap arbitrary byte arrays; not just those coming from a I/O class in `java.nio`. You really should not hand code your own extraction of primitive values if at all possible (i.e. bit shifting and so forth) since it is easy to get this wrong, the code is the same for every instance of the same type, and there are plenty of standard classes that provide this for you.
For example:
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;
}
}
Now, to create one, just call `Data.createFromBytes(byteArray)`.
Note that Java does not have unsigned integer variables, but these will be retrieved with the exact same bit pattern. So anything where the high-order bit is not set will be exactly the same when used. You will need to deal with the high-order bit if you expected that in your unsigned numbers. Sometimes this means storing the value in the next larger integer type (byte -> short; short -> int; int -> long).
Edit: Updated the example to show how to convert a `short` (16-bit signed) to an `int` (32-bit signed) with the unsigned value with `tc_2_as_int`.
Note also that if you cannot change the byte-order and it is not in network order, then `java.nio.ByteBuffer` can still serve you here with `buf.order(ByteOrder.LITTLE_ENDIAN);` before retrieving the values.
Problem
I have a C structure that is sent over some intermediate networks and gets received over a serial link by a java code. The Java code gives me a byte array that I now want to repackage it as the original structure. Now if the receive code was in C, this was simple. Is there any simple way to repackage a byte[] in java to a C struct. I have minimal experience in java but this doesnt appear to be a common problem or solved in any FAQ that I could find. FYI the C struct is ``` 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; ```