如何将以下“标记的联合”结构映射到JNA? libvterm
(link to source code)使用此结构。
/**
* Tagged union storing either an RGB color or an index into a colour palette
*/
typedef union {
/**
* Tag indicating which union member is actually valid. This variable
* coincides with the `type` member of the `rgb` and the `indexed` struct
* in memory. */
uint8_t type;
struct {
uint8_t type;
uint8_t red, green, blue;
} rgb;
struct {
uint8_t type;
uint8_t idx;
} indexed;
} VTermColor;
答案 0 :(得分:2)
尽管有许多可用的映射(使用正确的方法来获取值的任何32位结构),但直接映射此映射的规范方法是使用JNA的Union类。联盟将包含三个要素;您可以定义的byte
或结构RGB
(可以使用Union的内部类),也可以定义的结构Indexed
(同样可以是内部类) 。
Union
将在本机侧为最大的元素(32位)分配足够的内存,并且在给定结构选项的情况下,您可以确保得到的32位C端的前8位内存将包含type
字段;根据该值,您将知道剩余的24位中包含什么。
如果您查看映射source code of JNA's Variant class的tagged union VARIANT,您会发现它的实现稍微复杂一些。 _VARIANT
类包含这五个元素,类似于并集中的3个元素:
public VARTYPE vt;
public short wReserved1;
public short wReserved2;
public short wReserved3;
public __VARIANT __variant;
对于联合,只有__variant
的一个值有效。在这种情况下,在此处设置类型:
public void setVarType(short vt) {
this._variant.vt = new VARTYPE(vt);
}
更一般而言,您可以查看外部的VARIANT
类,该类使用Union类setType()
方法来确定是否还有一个有效值:它设置了一个与活动字段相对应的字符串(在此在构造函数中设置的大小写"_variant"
)。 (您也可以使用类而不是字符串进行设置。)
在您的情况下,您将需要基于类型值进行初始化,因此将以type
作为默认值开始,读取其值,然后进行切换。
您可以这样定义您的联合:
public class VTermColor extends Union {
public class RGB extends Structure {
public byte type;
public byte red;
public byte green;
public byte blue;
}
public class Indexed extends Structure {
public byte type;
public byte idx;
}
public byte type;
public RGB rgb;
public Indexed indexed;
public VTermColor() {
// initialize knowing only the type, read its value
this.setType("type");
this.read();
// switch union based on type, re-read
if ((this.type & VTERM_COLOR_TYPE_MASK) == VTERM_COLOR_RGB) {
this.setType("rgb");
} else {
this.setType("indexed");
}
this.read();
}
public VTermColor(Pointer p) {
super(p);
// same remaining code as above
}
}
您可能想创建其他一些getter方法,以在返回适当的字段之前检查type
值。
如开头所述,任何32位数据结构都可以使用。有点骇人听闻的选择(以更少的代码牺牲了可读性和类型安全性)可以始终使用上面定义的4字节RGB
结构。 type
的吸气剂将始终有效,而red
,green
和blue
的吸气剂将在有效时起作用,否则,您可以为{{1}创建吸气剂}只会读取idx
的值。