如何使用 JNA 从 Java 传递 int 作为C++函数参数
How to pass int as a C++ function parameter from Java using JNA
我目前正在做一个项目,该项目需要开发一个本机DLL(C++年(,以便Java应用程序访问。我选择了 JNA 作为桥接工作,但我在将正确的 int 值从 Java 传递到C++函数时遇到了问题。
简而言之,我有一个函数,它接受 int 值作为 C++ 中的参数:(剥离代码并重命名方法以保持机密性(
JAVALINK_EXPORT SomeStructure WINAPI GetSomeStructureFromIndex(int index) {
std::string debugMsg("Received index of ");
debugMsg.append(toString(index));
OutputDebugString(debugMsg.c_str());
SomeStructure result = defaultStructure;
if (index >= 0 && index < structListSize)
result = structList[index];
return result;
}
toString
是一种简单的方法,它使用 std::stringstream
将任何数据类型的值转换为std::string
。实现如下:
template <class T>
inline std::string toString (const T& t) {
std::stringstream ss;
ss << t;
return ss.str();
}
SomeStructure
是从我在代码中使用的实际结构重命名的。 structList
是一组SomeStructure
。 structListSize
和 structList
都是共享内存中的全局变量。
这是 DLL 的 Java 接口中的方法签名:
SomeStructure.ByValue GetSomeStructureFromIndex(int index);
这就是我在 Java 中将该方法用于测试用例的方式:
SomeStructure.ByValue received = library.GetSomeStructureFromIndex(1);
library
是使用 Native.loadLibrary
生成的 DLL 文件(StdCallLibrary
的子类(接口的实例。当上面的代码在 Java 中执行时,我在 Windows 调试输出中得到类似于以下输出的内容:
Received index of 86701080
(如果我在从数组中获取结构之前省略了对行if (index >= 0 && index < structListSize)
index
的检查,程序将继续遇到访问冲突错误(
86701080
可以是任意值。我意识到它会根据导出函数的签名而变化。我在这里错过了什么吗?如果函数签名已void PrintIndex(int index)
,函数将正确接收预期值 1
编辑(0(:我已经修改了示例代码以更紧密地匹配实际代码。
编辑(1(:根据@technomage的指针,我已经开始对所有收集返回结构的方法签名和变量使用 ByValue
。
编辑(2(:与C++中的SomeStructure
结构相比,Java 类SomeStructure
有一个额外的变量和一个 Java 方法。我目前正在测试这是否是导致差异的原因。
问题已解决
@technomage解释说,对于C++函数按预期解释其参数和返回值,用作返回类型的结构(以及用作函数参数的结构(的大小不应与Java对应项不同。在 SomeStructure
的情况下,可以在 C++ 中使用 sizeof(SomeStructure)
和在 Java 中使用 SomeStructure.size()
进行检查。
基本上,发生的事情是SomeStructure
结构的大小与其Java表示形式不同。 SomeStructure
包含一个固定长度的数组,如下面的代码所示:
#define MAX_LIST_SIZE 256
typedef struct {
int list[MAX_LIST_SIZE];
int length;
} SomeStructure;
但是,Java 表示形式没有指定固定长度数组的大小。 list
被初始化为包含单个值 0
。
package model;
import com.sun.jna.Structure;
public class SomeStructure extends Structure {
public static class ByValue extends SomeStructure implements Structure.ByValue { }
public int[] list = {0};
public int length = 0;
}
我通过将错误的初始化语句替换为以下内容来解决问题:
private static final int MAX_LIST_SIZE = 256;
public int[] list = new int[MAX_LIST_SIZE];
注意:整数常量MAX_LIST_SIZE
声明private
以使其仅供 Java 使用。
进行所有这些修改后,我的代码运行良好,不再遇到访问违规。
WINAPI"意味着stdcall调用约定,但你必须查看宏的本地定义才能确定。 如果是这样,您需要StdCallLibrary
而不是Library
。 这可能会影响您传入的index
论点。
您还复制了结构(通过值语义(,而不是指向它的指针。 当您按值传递结构或按值返回结构时,您需要告诉 JNA 您正在这样做。
编辑
确保SomeStructure.size()
与本机sizeof(SomeStructure)
匹配。 通常,通过值返回的结构实现,使得调用方在堆栈上分配内存,并将隐式指针传递给被调用方,然后被调用方写入该内存。 如果调用方和被调用方在该内存的大小上存在分歧,则可能会影响堆栈上的其他内容(例如参数和返回值(。 您还可以向函数添加更多参数并打印其值(作为十六进制(,以获得堆栈上内容的近似值。 如果您传入可识别的参数(例如 0x12345678(,通常会很清楚是什么将堆栈推向或拉向错误的方向。
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 将Ref对象作为类成员
- 虚拟决赛作为安全
- 在VS2010-VS2015下编译时,如何使用decltype作为较大类型表达式的LHS
- 使用指向成员的指针将成员函数作为参数传递
- 我应该使用什么来代替void作为变体中的替代类型之一
- 何时提供默认参数作为模板参数
- 如何将 I->getType() 作为参数传递给 llvm 中的 CreateCall?
- C++使用数组作为多维数组,尽管将其初始化为带有指针的 1D
- C++匿名结构作为std::映射值
- C++:如何使函数只返回作为列表一部分的字符串
- 如何制作一个将函数作为参数的类方法
- 如何在C++中使用非静态成员函数作为回调函数
- 修改函数中的指针(将另一个指针作为参数传递)
- Clang bug?使用指针作为模板参数
- 函数作为模板参数,是否对返回类型强制约束
- 在C++中传递给函数时,为什么要指定数组大小作为参数
- 为什么 Clang 不允许"and"作为函数名称?
- 为什么 std::function 可以作为 std::not2 的参数?