结构包含char的内存访问无效*

vx6bjr1n  于 2021-07-08  发布在  Java
关注(0)|答案(2)|浏览(576)

我正试图绘制一个包含一些 char * 使用jna的字段。我得到以下例外:
线程“main”java.lang中出现异常。错误:内存访问无效
这是我的c代码:
调用的函数的签名

extern "C" MATHLIBRARY_API ERR ErrorTest();

我以c示例实现为例:

ERR sngErrorTest() {
    ERR err;
    char message[] = "My message";
    char filename[] = "My file Name";

    err.errorCode = OK;
    err.errorDetails.fileName = NULL;
    err.errorDetails.lineNumber = 1;
    err.errorDetails.message = message;
    err.errorDetails.fileName = filename;
    return err;
}

c类型定义:

typedef enum {
    OK = 0, 
    ERR_ONE,
    ERR_TWO,
    ERR_THREE,
    ERR_FOUR,
    ERR_FIVE,
    ERR_SIX,
} ERR_CODE;

typedef struct {
    char *fileName; 
    char *message; 
    int lineNumber; 
} ERR_DETAILS;

typedef struct {
    ERR_CODE errorCode; 
    ERR_DETAILS errorDetails; 
} ERR;

以下是我的java代码:

public interface IFunctions extends Library {
    public static class ERR_DETAILS extends Structure {
        public static class ByValue extends ERR_DETAILS implements Structure.ByValue {}
        public static class ByReference extends ERR_DETAILS implements Structure.ByReference {}
        public Pointer fileName; 
        public Pointer message; 
        public int lineNumber; 
        @Override
        protected List<String> getFieldOrder() {
            return Arrays.asList(new String[] { "fileName", "message","lineNumber"});
        }
    }
    public static class ERR_CODE {
        public static int OK = 0; 
        public static int ERR_ONE = 1;
        public static int ERR_TWO = 2;
        public static int ERR_THREE = 3;
        public static int ERR_FOUR = 4;
        public static int ERR_FIVE = 5;
        public static int ERR_SIX = 6;

    }

    public static class ERR extends Structure {
        public static class ByValue extends ERR implements Structure.ByValue {}
        public static class ByReference extends ERR implements Structure.ByReference {}
        public ERR_CODE errorCode;
        public ERR_DETAILS errorDetails;
        @Override
        protected List<String> getFieldOrder() {
            return Arrays.asList(new String[] { "errorCode", "errorDetails"});
        }
    }

    public ERR ErrorTest();
    }

下面是我的java测试主类:

ERR err = IFunctions.ErrorTest();

关于char*类型,我用字符串替换了指针,但得到了相同的问题。
一旦我以指针的形式检索到filename项,如何获取filename引用的值?它是 err.errorDetails.fileName.getString(0); ?
因此,我尝试隔离每种类型的结构,并创建了以下c函数作为示例:
签名:

extern "C" MATHLIBRARY_API ERR_CODE ErrorCode();

c实施:

ERR_CODE ErrorCode() {
    ERR_CODE err_code;
    err_code = OK;
    return err_code;
}

java声明

public interface IFunctions extends Library {
....
public ERR_CODE ErrorCode();
....
}

调用我的jna函数:

ERR_CODE errCode = IFunctions.ErrorCode();

在这种情况下,我得到以下错误:线程“main”java.lang.illegalargumentexception中的异常:函数errorcode中不支持的返回类型类err\u代码
我忘了关于枚举类型定义的一些想法了吗?

qojgxg4l

qojgxg4l1#

问题出在你的Map上 ERR_CODE 枚举。
jna没有 enum 类型,因为这些类型通常是32位整数。但是,您已经将它Map为一个普通java类(扩展对象),它没有任何jnaMap。
传统的Map绘制方法 enum 在jna中,是将int值 Package 在 interface . (这只是用于自文档化代码。实际上,你真正需要的是 int 值。)
所以你应该改变主意 ERR_CODE Map到:

interface ERR_CODE {
    int OK = 0; 
    int ERR_ONE = 1;
    int ERR_TWO = 2;
    int ERR_THREE = 3;
    int ERR_FOUR = 4;
    int ERR_FIVE = 5;
    int ERR_SIX = 6;
}

注意 public 以及 static 修改器对于接口成员是多余的。
那你也该换衣服了 ERR 结构Map到:

@FieldOrder({"errorCode", "errorDetails"})
class ERR extends Structure {
    public int errorCode; // ERR_CODE
    public ERR_DETAILS errorDetails;
}

注意,我刚刚绘制了 enum 作为一个 int ,使用注解字段表示 int 代表。
这里有一个潜在的对齐问题,它可能依赖于平台。通常最大字节大小用于对齐,因为 ERR_DETAILS Map中包含8字节指针,4字节int和下一个元素的字节边界之间可能不对齐(例如。, errorDetails 可以从偏移量开始 0x8 而不是 0x4 . 要解决此问题,可能需要在结构中设置对齐类型,将Map更改为:

@FieldOrder({"errorCode", "errorDetails"})
class ERR extends Structure {
    public int errorCode; // ERR_CODE
    public ERR_DETAILS errorDetails;

    public ERR() {
        super();
        setAlignType(ALIGN_NONE);
    }
}

另外,我还删除了不必要的 ByValue 以及 ByReference 子类。你很少需要在结构内部定义这些, ByValue 是默认的和in方法参数 ByReference 是默认值,您只需要在很少的情况下定义这些值,而不使用默认值。
我还使用了jna 5.x @FieldOrder 而不是重写方法。
你可以用 String 在的结构Map中 char * 而不是 Pointer ,尽管 Pointer 以及 getString() 如果您选择保留Map,则是正确的处理方法:

@FieldOrder({"fileName", "message", "lineNumber"})
class ERR_DETAILS extends Structure {
    public String fileName; 
    public String message; 
    public int lineNumber; 
}
xcitsw88

xcitsw882#

最后我得到了对我的问题的回应。
在我的jna Package 器中,我必须显式地定义我的函数按值返回结构,而不是按引用返回结构,因为jna默认是这样做的。正如jnaapi中关于结构类的描述:“当用作函数参数或返回值时,这个类对应于struct*。当用作另一个结构中的字段时,它对应于struct。标记接口structure.byreference和structure.byvalue可用于更改默认行为。“
因此,解决方案如下:

public interface IFunctions extends Library {
...
public ERR.ByValue ErrorTest();
}

没有什么可以改变的。谢谢你的帮助。

相关问题