使用 Java Native Access 将结构从 C 映射到 Java 时出现问题

问题描述 投票:0回答:1

我从项目中提取了以下 C 头文件,我想使用 JNA 将其映射到 Java:

...

typedef size_t ObjectHandle;

typedef const char *FfiStr;

typedef struct FfiList_FfiStr {
  size_t count;
  const FfiStr *data;
} FfiList_FfiStr;

typedef struct FfiList_FfiStr FfiStrList;

int create_schema(FfiStr schema_name,
                  FfiStr schema_version,
                  FfiStr issuer_id,
                  FfiStrList attr_names,
                  ObjectHandle *result_p);
...

我找不到 FfiStr 和 FfiStrList 类型到 Java 的正确映射。

这是我在 Java 中尝试过的映射:

public interface CredLibrary extends Library {
    CredLibrary INSTANCE = (CredLibrary) Native.load("credlibrary", CredLibrary.class);

    public class FfiStr extends Structure {
        public class ByReference extends FfiStr implements Structure.ByReference {};
        public String FfiStr;

        public FfiStr(){
            FfiStr= new String();
        }

        public FfiStr(String s) {
            FfiStr = new String(s);
        }

        @Override
        protected List getFieldOrder() {
            return Arrays.asList("FfiStr");
        }
    }

    public class FfiList_FfiStr extends Structure{
        public Size_t count;
        public FfiStr.ByReference[] data;

        public FfiList_FfiStr(String[] attr){
            super();
            count = new Size_t(attr.length);
            data= new FfiStr.ByReference[attr.length];
        }

        @Override
        protected List getFieldOrder() {
            return Arrays.asList("count", "data");
        }
    }

    int create_link_secret(PointerByReference link_secret_p);
    int generate_nonce(PointerByReference nonce_p);
    int create_schema(FfiStr schema_name, FfiStr schema_version, FfiStr issuer_id,FfiList_FfiStr attr_names, IntByReference result_p);

}

第一个 create_link_secret 和generate_nonce 函数工作正常,create_schema 不起作用。

这是我尝试过的测试:

CredLibrary.FfiStr schema_name= new CredLibrary.FfiStr("test");
CredLibrary.FfiStr schema_version = new CredLibrary.FfiStr("v1");
CredLibrary.FfiStr issuer_id =new CredLibrary.FfiStr( "123");


CredLibrary.FfiList_FfiStr attrib = new CredLibrary.FfiList_FfiStr(attr);
IntByReference pref3= new IntByReference();
int c= lib.anoncreds_create_schema(schema_name,schema_version,issuer_id,attrib,pref3);
int p3 =pref3.getValue();

Log.i("TEST","Value of the schema created:"+String.valueOf(c));

更准确地说,create_schema 输出 1,这是输入值相关问题的 ErrorCode 值。所以这可能意味着我从 C 到 Java 的结构之间的映射不正确。所以我可能在 Java 映射代码中做错了什么。

可以指出我做错了什么吗?

我想也许 FfiStr 是错误的,因为 Java FfiStr 有一个属性,而 C 没有。

java jna
1个回答
0
投票

C

const char *
映射到 Java
String
。 JNA 有
size_t
的映射,具体取决于您的操作系统。

您通常不需要也不应该添加

ByReference
标签。这些增加了另一层指针间接寻址,这通常是错误的。内联结构中您不需要指针,JNA 默认为 ByValue。作为函数/方法参数,您通常需要指针,而 JNA 在这里默认为 ByReference。

您的结构中确实有一个字符串数组,但 JNA 要求在初始化时声明数组长度。如果您在 Java 端声明它,那么这是可行的,但如果从本机端读取它,则需要一些额外的步骤来覆盖结构上的

read()

您可以删除

FfiStr
结构并使用
String
进行该映射。

String

如果您决定将字符串包装在结构中(例如,为了类型安全),请不要在其上使用

ByReference
,因为
String
映射已经包含指针。此映射本质上与键入的
String
:

相同
@FieldOrder ({"FfiStr"})
public class FfiStr extends Structure {
    public String FfiStr;

    public FfiStr(String s) {
        FfiStr = s;
    }
}

对于你的第二个结构,它有点复杂。当声明一个Structure时,JNA为其分配内存,因此它需要知道数组的大小。所以你需要给数据一个非零的初始化,然后在构造函数中覆盖该值并重新分配内存:

@FieldOrder ({"count", "data"})
public class FfiList_FfiStr extends Structure{
    public Size_t count;
    public String[] data = new String[1];

    public FfiList_FfiStr(String[] attr){
        count = new Size_t(attr.length);
        data = new String[attr.length];
        // or new FfiStr[attr.length]; if defined above
        allocateMemory();
    }

    // if reading from native you'll need to override read()
    // to do similar memory reallocation
}
© www.soinside.com 2019 - 2024. All rights reserved.