簡體   English   中英

JNA將Java布爾值映射到-1整數?

[英]JNA maps Java boolean to -1 integer?

當我在JNA結構中傳遞一個boolean值時,我正在使用的本機庫中收到一個令人驚訝的警告:

value of pCreateInfo->clipped (-1) is neither VK_TRUE nor VK_FALSE

在此庫中, VK_TRUEVK_FALSE分別為#defined 1和0。

結構本身並不是特別復雜,其他一切似乎都在工作(本機庫似乎將'undefined'布爾值視為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;
}

如果clipped字段為false則沒有警告,如果是,則我收到警告 - 看來JNA映射為true為整數-1?

這個庫使用的本機布爾值不多,但只要一個設置為true,我就會得到相同的行為(並且其他一切工作正常)。

特別是,如果我將clipped更改為int並將值顯式設置為1或0,一切正常!

是-1 JNA布爾默認值true

如果是這樣,我將如何過度使用類型映射?

或者我應該只使用int '手動'?

JNA通過libffi映射到本機庫。 libffi沒有bool類型,因此必須使用其他映射 - JNA的默認類型映射選擇將boolean 映射ffi_type_uint32 這在結構中起作用,因為它恰好匹配32位映射大小,但不匹配定義:在C中,0為false,任何非零都為真。 僅當本機類型也是boolean ,此0 /非零解釋才重新獲得false / true。

使用Web搜索FFIJNIboolean關鍵字可以發現多個例子如這一個這一個 ,其中當庫經由FFI或JNI訪問和不符合為布爾值0/1的要求無法預料的結果發生。 后一個示例與此情況非常相似,其中真正的Java boolean被解釋為具有非1值的C int

在FFI和您的庫之間的某個地方,可能在編譯的字節代碼和/或平台/編譯器相關的類型轉換中,可能是按位“不”應用於0x00000000 ,將其轉換為0xffffffff仍然是'true '在C.

最重要的是,JNA默認將Java布爾值false映射到32位本機值0,並將Java布爾true設置為32位本機值(非0),這就是可以假設的全部值。 如果您的庫要求為true ,則整數值為1,或者使用您可以專門設置的整數類型,或者使用自定義類型映射為boolean ,將int設置為0或1。 JNA的W32APITypeMapper有一個示例,即Windows BOOL類型轉換為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位整數編輯:正如你在答案中指出的那樣,添加你自己的類型映射器以更好地處理這些int值是很簡單的!

(當我查看類型映射時,您可能會發現IntByReferencepQueueFamilyIndices字段的Pointer更好的映射。) (您的映射對於可變長度的int數組是正確的。)

事實上,事實證明,在各種原生圖書館結構有很多布爾,其實幾百個! 保留布爾字段的意圖是很好的,而不是僅僅因為實現強制執行該限制而將它們全部替換為int 所以我花了一些時間研究JNA類型轉換......

JNA支持在創建本機庫時使用作為附加參數傳遞給Native::loadTypeMapper映射自定義類型。 使用Java-to / from-native轉換器接口TypeConverter定義自定義類型映射。

定義一個自定義布爾包裝器,它將Java boolean映射到C int ,從1 = true和0 = false,這是非常簡單的:

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;
    }
}

因此注冊了類型映射器:

final DefaultTypeMapper mapper = new DefaultTypeMapper();
mapper.addTypeConverter(VulkanBoolean.class, VulkanBoolean.MAPPER);
...

final Map<String, Object> options = new HashMap<>();
options.put(Library.OPTION_TYPE_MAPPER, mapper);
Native.load("vulkan-1", VulkanLibrary.class, options);

如果一個人寫一個小庫結構的極少數(通常情況下),但有點頭疼的,當你有幾個微不足道的-如果有問題的結構(s)是JNA庫接口 定義然而這僅適用一百種方法和~500種結構(代碼生成)。

或者,可以在結構構造函數中指定類型映射器,但這需要:

  1. 檢測 每個需要自定義映射的結構。

  2. 每個自定義類型都必須另外實現 NativeMapped以便JNA可以確定自定義類型的本機大小(不知道為什么基本上必須指定兩次相同的信息)。

  3. 每個自定義類型都必須支持默認構造函數。

這些都不是特別令人愉快的選擇,如果JNA支持覆蓋這兩種情況的全局類型映射,那就太好了。 我猜我需要使用type-mapper重新生成所有結構的代碼。 嘆。

但是,只有在JNA庫接口定義了相關結構時,這才有效。 一個簡單的解決方法是在庫中定義基類結構並從中擴展所有其他結構:

 public interface Library { abstract class VulkanStructure extends Structure { protected VulkanStructure() { super(VulkanLibrary.TYPE_MAPPER); } } ... } public class VkSwapchainCreateInfoKHR extends VulkanStructure { ... } 

我使用相同的機制自動將~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。

 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; ... } 

(最近在這里找到了一個完整的例子)。

希望所有這些莫名其妙的幫助有人試圖了解JNA的變幻莫測。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM