JNA将Java布尔映射为-1整数?
在JNA结构中传递JNA将Java布尔映射为-1整数?,java,jna,Java,Jna,在JNA结构中传递boolean值时,我使用的本机库发出了一个惊人的警告: value of pCreateInfo->clipped (-1) is neither VK_TRUE nor VK_FALSE 在此库中,VK_TRUE和VK_FALSE分别定义为1和0 结构本身并不特别复杂,其他一切似乎都正常工作(本机库似乎将“未定义”布尔值视为false),但无论如何,这里是: public class VkSwapchainCreateInfoKHR extends Structur
boolean
值时,我使用的本机库发出了一个惊人的警告:
value of pCreateInfo->clipped (-1) is neither VK_TRUE nor VK_FALSE
在此库中,VK_TRUE
和VK_FALSE
分别定义为1和0
结构本身并不特别复杂,其他一切似乎都正常工作(本机库似乎将“未定义”布尔值视为false),但无论如何,这里是:
public class VkSwapchainCreateInfoKHR extends Structure {
public int sType;
public Pointer pNext;
public int flags;
public Pointer surface;
public int minImageCount;
public int imageFormat;
public int imageColorSpace;
public VkExtent2D imageExtent;
public int imageArrayLayers;
public int imageUsage;
public int imageSharingMode;
public int queueFamilyIndexCount;
public Pointer pQueueFamilyIndices;
public int preTransform;
public int compositeAlpha;
public int presentMode;
public boolean clipped; // <--------- this is the field in question
public Pointer oldSwapchain;
}
公共类VkSwapchainCreateInfoKHR扩展结构{
公共int sType;
公共指针pNext;
公共国旗;
公共指针表面;
公共int最小计数;
公共int图像格式;
公共图像色彩空间;
公共VkExtent2D图像范围;
公共图像阵列专家;
公共用途;
公共图像共享模式;
公共int-queueFamilyIndexCount;
公共指针pquefamilyindice;
公共信息预转换;
公共综合医院;
公共int呈现模式;
公共布尔剪裁;//JNA通过libffi
映射到本机库。libffi
中没有bool
类型,因此必须使用其他映射——JNA选择将boolean
映射到ffi\u类型uint32
。这在结构中起作用因为它恰好与32位映射大小匹配,但与定义不匹配:在C中,0为false,任何非零的值都为true。只有当本机类型也是boolean
时,此0/非零解释才会恢复为false/true
使用FFI
或JNI
和boolean
关键字进行web搜索可以发现多个示例,例如,当通过FFI或JNI访问库时,会出现不可预测的结果,并且不符合布尔值的0/1要求。后一个示例与真正的Javaboolean
被解释为值不是1的Cint
在FFI和您的库之间的某个地方,可能在编译的字节码和/或平台/编译器相关的类型转换中,很可能对0x00000000
应用了按位“not”,将其转换为0xffffff
,在C中仍然是“true”
底线是,JNA默认情况下会将Java booleanfalse
映射为32位本机值0,将Java booleantrue
映射为32位本机值而非0,这就是可以假设的所有内容。如果您的库要求true
的整数值为1,请使用可以指定的整数类型对boolean
进行逻辑设置或使用自定义类型映射,为您将int
设置为0或1。JNA有一个将WindowsBOOL
类型转换为1或0的示例
在本例中,假设您正在映射VkSwapchainCreateInfoKHR结构,clipped
的类型是VkBool32:
typedef struct VkSwapchainCreateInfoKHR {
VkStructureType sType;
const void* pNext;
VkSwapchainCreateFlagsKHR flags;
VkSurfaceKHR surface;
uint32_t minImageCount;
VkFormat imageFormat;
VkColorSpaceKHR imageColorSpace;
VkExtent2D imageExtent;
uint32_t imageArrayLayers;
VkImageUsageFlags imageUsage;
VkSharingMode imageSharingMode;
uint32_t queueFamilyIndexCount;
const uint32_t* pQueueFamilyIndices;
VkSurfaceTransformFlagBitsKHR preTransform;
VkCompositeAlphaFlagBitsKHR compositeAlpha;
VkPresentModeKHR presentMode;
VkBool32 clipped;
VkSwapchainKHR oldSwapchain;
} VkSwapchainCreateInfoKHR;
在哪里
typedef uint32_t VkBool32;
因此,int
是正确的映射——您需要将clipped
映射到32位整数Edit:正如您在回答中指出的,添加自己的类型映射器以更好地处理这些int
值非常简单
(当我在查看类型映射时,您可能会发现IntByReference
对于pQueueFamilyIndices
字段,映射比Pointer
更好。)(对于可变长度int
数组,您的映射是正确的。)事实上,在各种本机库结构中有很多布尔值,事实上有几百个!最好保留布尔值字段的意图,而不是仅仅因为实现强制了该限制就用int
替换它们。因此我花了一些时间研究JNA类型转换
当创建本机库时,JNA支持使用作为附加参数传递给Native::load
的TypeMapper
映射自定义类型。自定义类型映射是使用Java到/从本机转换器接口TypeConverter
定义的
定义一个自定义布尔包装器,用1=true和0=false将Javaboolean
映射到Cint
,这相当简单:
public final class VulkanBoolean {
static final TypeConverter MAPPER = new TypeConverter() {
@Override
public Class<?> nativeType() {
return Integer.class;
}
@Override
public Object toNative(Object value, ToNativeContext context) {
if(value == null) {
return VulkanBoolean.FALSE.toInteger();
}
else {
final VulkanBoolean bool = (VulkanBoolean) value;
return bool.toInteger();
}
}
@Override
public Object fromNative(Object nativeValue, FromNativeContext context) {
if(nativeValue == null) {
return VulkanBoolean.FALSE;
}
else {
final int value = (int) nativeValue;
return value == 1 ? VulkanBoolean.TRUE : VulkanBoolean.FALSE;
}
}
};
public static final VulkanBoolean TRUE = VulkanBoolean(true);
public static final VulkanBoolean FALSE = VulkanBoolean(false);
private final boolean value;
private VulkanBoolean(boolean value) {
this.value = value;
}
public boolean value() {
return value;
}
public int toInteger() {
return value ? 1 : 0;
}
}
我使用了相同的机制,将~300个代码生成的枚举自动神奇地映射到本机int
,当前看起来如下所示:
public enum VkSubgroupFeatureFlag implements IntegerEnumeration {
VK_SUBGROUP_FEATURE_BASIC_BIT(1),
VK_SUBGROUP_FEATURE_VOTE_BIT(2),
...
private final int value;
private VkSubgroupFeatureFlag(int value) {
this.value = value;
}
@Override
public int value() {
return value;
}
}
目前,引用“枚举”的所有结构实际上都是作为int
实现的。使用IntegerEnumeration
的自定义类型转换器,字段类型可以是实际的Java枚举,JNA将处理与整数值之间的转换(我目前必须手动完成)。这显然使结构的类型更加安全,更加清晰,并且明确地引用了实际的枚举,而不是int
-nice
i、 e
(最近发现了一个这样做的例子)
希望所有这些胡言乱语都能帮助人们了解JNA的变幻莫测。这里有些可疑之处。我认为正确的代码应该具有布尔字段的实际位模式,而不会进入方程中。布尔值有两种潜在状态…“真”和“假”…句点。那么,发生了什么事正在布尔值和整数值之间进行映射?该结构是否确实包含格式不正确的“true”位模式,或者是否有其他东西将值转换为int,然后另一个东西需要不同的整数表示形式?给定常量定义,代码是否希望该字段为整数值?也许它只需要是一个int。什么本机库定义了VK_TRUE?-这可能是任何数据库定义的函数吗?保存此结构?@Steve No databases,JNA用于调用本机l
public interface Library {
abstract class VulkanStructure extends Structure {
protected VulkanStructure() {
super(VulkanLibrary.TYPE_MAPPER);
}
}
...
}
public class VkSwapchainCreateInfoKHR extends VulkanStructure { ... }
public enum VkSubgroupFeatureFlag implements IntegerEnumeration {
VK_SUBGROUP_FEATURE_BASIC_BIT(1),
VK_SUBGROUP_FEATURE_VOTE_BIT(2),
...
private final int value;
private VkSubgroupFeatureFlag(int value) {
this.value = value;
}
@Override
public int value() {
return value;
}
}
public class VkSwapchainCreateInfoKHR extends VulkanStructure {
...
public int flags;
public Pointer surface;
public int minImageCount;
// The following fields were int but are now the Java enumerations
public VkFormat imageFormat = VkFormat.VK_FORMAT_UNDEFINED;
public VkColorSpaceKHR imageColorSpace;
...
}