-
The documentation describes how to define primitives in a struct but doesn't mention inner stucts. I have a legacy codebase which relies on
|
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
It depends on what the C code you're trying to map looks like. If it uses an inner Struct reference meaning a pointer to a Struct such as: typedef struct range {
int min;
int max;
} range_t;
struct outer {
int mean;
range_t *range;
}; Then use public class Range extends Struct {
private final Signed32 min;
private final Signed32 max;
public Range(Runtime runtime) {
super(runtime);
this.min = new Signed32();
this.max = new Signed32();
}
// methods here like setters getters or utilities
}
public class Outer extends Struct {
private final Signed32 mean;
private final StructRef<Range> range;
public Outer(Runtime runtime) {
super(runtime);
this.mean = new Signed32();
this.range = new StructRef<Range>(Range.class);
}
} If it uses an inner struct i.e. no pointer like the following: typedef struct range {
int min;
int max;
} range_t;
struct outer {
int mean;
range_t range;
}; Then instead of public class Range extends Struct {
private final Signed32 min;
private final Signed32 max;
public Range(Runtime runtime) {
super(runtime);
this.min = new Signed32();
this.max = new Signed32();
}
// methods here like setters getters or utilities
}
public class Outer extends Struct {
private final Signed32 mean;
private final Range range; // no wrapping needed
public Outer(Runtime runtime) {
super(runtime);
this.mean = new Signed32();
this.range = inner(new Range(runtime)); // need to create Range first!
}
} You can verify this by checking the size of the structs using the static method Inner Structs may cause problems because of padding meaning the struct's size in C is (sometimes much) larger than it appears in Java because of padding (extra alignment bytes at the end that compilers add for performance). For example in Java: public class Range extends Struct {
private final Signed32 min;
private final Signed32 max;
public Range(Runtime runtime) {
super(runtime);
this.min = new Signed32();
this.max = new Signed32();
}
public int size() {
return Struct.size(this); // will probably return 8 bytes because Signed32 is 4 bytes and we have 2 of them
}
} but the same struct in C may surprise you with something like: typedef struct range {
int min;
int max;
} range_t;
printf("struct size: %lu", sizeof(range_t));
// may be unpredictable like 12 or 16 or something
// but always at least 8 because `int`s are 4 (on most machines) and we have 2 of them In this case if you have access to the original C library it may be useful to add a couple of size functions to help you out in Java for padding, something like this in C: long sizeof_range_t(void) {
return sizeof(range_t);
} This way no matter what the compiler, architecture, OS etc you will always have access to the expected struct size in Java which you can then use for padding like this: public class Range extends Struct {
private final Signed32 min;
private final Signed32 max;
private final Padding padding;
public Range(Runtime runtime) {
super(runtime);
this.min = new Signed32();
this.max = new Signed32();
int paddingSizeBytes = library.sizeof_range_t() - Struct.size(this);
this.padding = new Padding(/*nativeType=*/ NativeType.SCHAR, paddingSizeBytes);
// we use SCHAR because it is always 1 byte in size
assert(this.size() == library.sizeof_range_t()) // shouldn't fail
}
public int size() {
return Struct.size(this); // will now return what C returns too
}
} You may not need the padding though depending on the C code, make sure you test your code thoroughly to ensure Java is getting correct expected data, otherwise you will often get silent failures in the form of corrupt or useless data because of incorrect memory access meaning the struct is using or reading memory incorrectly. Yeah we need to get this documented better, both in the user docs and in the javadocs. I will probably do this at some point in the coming months. Anyway hope this answered your issue. |
Beta Was this translation helpful? Give feedback.
-
This was really helpful. Thank you @basshelal. |
Beta Was this translation helpful? Give feedback.
It depends on what the C code you're trying to map looks like.
If it uses an inner Struct reference meaning a pointer to a Struct such as:
Then use
StructRef
like below: