使用包含 char* 的结构进行无效内存访问
Invalid memory access with Structure containing char*
我正在尝试使用 JNA 映射包含一些 char *
字段的结构。我收到以下异常:
Exception in thread "main" java.lang.Error: Invalid memory access
这是我的 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 测试主要 class :
ERR err = IFunctions.ErrorTest();
- 关于 char * 类型,我用 String 替换了 Pointer,但我遇到了同样的问题。
- 一旦我将 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
中不支持 return 类型 class ERR_CODE
我是不是忘记了关于枚举类型定义的一些想法?
问题出在 ERR_CODE
枚举的映射中。
JNA 没有 enum
类型的直接映射,因为这些类型通常是 32 位整数。但是,您已将其映射为没有任何 JNA 映射的普通 java class(扩展对象)。
在 JNA 中映射 enum
的常规方法是将 int 值包装在 interface
中。 (这只是为了自记录代码。实际上,您真正需要的只是 int
值。)
所以您应该将 ERR_CODE
映射更改为:
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
结构映射更改为:
@FieldOrder({"errorCode", "errorDetails"})
class ERR extends Structure {
public int errorCode; // ERR_CODE
public ERR_DETAILS errorDetails;
}
注意我刚刚将 enum
映射为 int
,使用注释字段表示 int
代表的特定类型(枚举)。
这里可能存在对齐问题,这可能与平台有关。通常最大字节大小用于对齐,并且由于 ERR_DETAILS
映射中包含 8 字节指针,因此 4 字节 int 和下一个元素的字节边界之间可能存在未对齐(例如,errorDetails
可能从 0x8
而不是 0x4
的偏移量开始。要解决此问题,您可能需要在结构中设置对齐类型,将映射更改为:
@FieldOrder({"errorCode", "errorDetails"})
class ERR extends Structure {
public int errorCode; // ERR_CODE
public ERR_DETAILS errorDetails;
public ERR() {
super();
setAlignType(ALIGN_NONE);
}
}
另请注意,我还删除了不必要的 ByValue
和 ByReference
subclasses。您很少需要定义它们——在结构内部,ByValue
是默认值,在方法参数中 ByReference
是默认值,您只需要在不使用默认值的极少数情况下定义它们。
我还使用了 JNA 5.x @FieldOrder
注释而不是覆盖方法。
您可以在 char *
的结构映射中使用 String
而不是 Pointer
,尽管 Pointer
和 getString()
是正确的处理方式如果您选择保留该映射:
@FieldOrder({"fileName", "message", "lineNumber"})
class ERR_DETAILS extends Structure {
public String fileName;
public String message;
public int lineNumber;
}
我的问题终于得到了回复。
在我的 JNA 包装器中,我必须明确定义我的函数 return 是一个值结构,而不是 JNA 默认完成的引用结构。
如 JNA API 中关于结构 class 所述:
“当用作函数参数或return值时,此class对应于struct*。
当用作另一个结构中的字段时,它对应于结构。
标记接口 Structure.ByReference 和 Structure.ByValue 可用于更改默认行为。"
于是解决方案如下:
public interface IFunctions extends Library {
...
public ERR.ByValue ErrorTest();
}
没有其他要更改的内容。
感谢您的帮助。
我正在尝试使用 JNA 映射包含一些 char *
字段的结构。我收到以下异常:
Exception in thread "main" java.lang.Error: Invalid memory access
这是我的 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 测试主要 class :
ERR err = IFunctions.ErrorTest();
- 关于 char * 类型,我用 String 替换了 Pointer,但我遇到了同样的问题。
- 一旦我将 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
中不支持 return 类型 class ERR_CODE我是不是忘记了关于枚举类型定义的一些想法?
问题出在 ERR_CODE
枚举的映射中。
JNA 没有 enum
类型的直接映射,因为这些类型通常是 32 位整数。但是,您已将其映射为没有任何 JNA 映射的普通 java class(扩展对象)。
在 JNA 中映射 enum
的常规方法是将 int 值包装在 interface
中。 (这只是为了自记录代码。实际上,您真正需要的只是 int
值。)
所以您应该将 ERR_CODE
映射更改为:
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
结构映射更改为:
@FieldOrder({"errorCode", "errorDetails"})
class ERR extends Structure {
public int errorCode; // ERR_CODE
public ERR_DETAILS errorDetails;
}
注意我刚刚将 enum
映射为 int
,使用注释字段表示 int
代表的特定类型(枚举)。
这里可能存在对齐问题,这可能与平台有关。通常最大字节大小用于对齐,并且由于 ERR_DETAILS
映射中包含 8 字节指针,因此 4 字节 int 和下一个元素的字节边界之间可能存在未对齐(例如,errorDetails
可能从 0x8
而不是 0x4
的偏移量开始。要解决此问题,您可能需要在结构中设置对齐类型,将映射更改为:
@FieldOrder({"errorCode", "errorDetails"})
class ERR extends Structure {
public int errorCode; // ERR_CODE
public ERR_DETAILS errorDetails;
public ERR() {
super();
setAlignType(ALIGN_NONE);
}
}
另请注意,我还删除了不必要的 ByValue
和 ByReference
subclasses。您很少需要定义它们——在结构内部,ByValue
是默认值,在方法参数中 ByReference
是默认值,您只需要在不使用默认值的极少数情况下定义它们。
我还使用了 JNA 5.x @FieldOrder
注释而不是覆盖方法。
您可以在 char *
的结构映射中使用 String
而不是 Pointer
,尽管 Pointer
和 getString()
是正确的处理方式如果您选择保留该映射:
@FieldOrder({"fileName", "message", "lineNumber"})
class ERR_DETAILS extends Structure {
public String fileName;
public String message;
public int lineNumber;
}
我的问题终于得到了回复。
在我的 JNA 包装器中,我必须明确定义我的函数 return 是一个值结构,而不是 JNA 默认完成的引用结构。 如 JNA API 中关于结构 class 所述: “当用作函数参数或return值时,此class对应于struct*。 当用作另一个结构中的字段时,它对应于结构。 标记接口 Structure.ByReference 和 Structure.ByValue 可用于更改默认行为。"
于是解决方案如下:
public interface IFunctions extends Library {
...
public ERR.ByValue ErrorTest();
}
没有其他要更改的内容。 感谢您的帮助。