如何通过本机函数的值 return?
How to return by value from native function?
我使用 Visual Studio 2017 编译了以下 C++ 方法:
extern "C" __declspec( dllexport )
Info* __stdcall GetInfo(InfoProvider* infoProvider)
{
static_assert(std::is_pod<Info>::value, "Must be Plain Old Data in order to be safely copied between DLL boundaries");
Info info = new Info();
Info->data1 = infoProvider->data1;
Info->data2 = infoProvider->data2;
return info;
}
在 Java 代码中,它由 Java 本机运行时使用具有以下签名的接口方法映射:
Info GetInfo(Pointer infoProvider);
final class Info extends Struct {
public final Signed32 data1;
public final Signed32 data2;
public R2VInfo(final Runtime runtime) {
super(runtime);
data1 = new Signed32();
data2 = new Signed32();
}
}
有效。
上面的C++方法导致内存泄漏,所以我想把它改成return result by value:
extern "C" __declspec( dllexport )
Info __stdcall GetInfo(InfoProvider* infoProvider)
{
static_assert(std::is_pod<Info>::value, "Must be Plain Old Data in order to be safely copied between DLL boundaries");
Info info{};
Info.data1 = infoProvider->data1;
Info.data2 = infoProvider->data2;
return info;
}
我使用相同的 Java JNR 映射:
Info GetInfo(Pointer infoProvider);
但它不起作用 - 访问冲突。调用本机方法,但有一些未处理的指针值。
如何在 JNR 中按值 return?
JNI 围绕旧的纯 K&R C 构建,以与所有可用的编译器兼容。从函数返回结构是在 C89 中引入的,并且在很晚的时候与 C++ 标准一起完全实现。今天,仍然可以在许多 java-friendly 环境(例如小型设备或 sim-cards)中找到这样的旧 C 编译器。所以我不认为JNI会升级到C89甚至C99。
对于您的情况,我建议编写一个额外的 C-code 来处理库函数的调用。代码可以通过两种方式实现:
- 对于
Info* __stdcall GetInfo(InfoProvider* infoProvider)
你应该这样写 free-function:
extern "C" __declspec( dllexport )
void __stdcall FreeInfo(Info* info)
{
static_assert(std::is_pod<Info>::value, "Must be Plain Old Data in order to be safely copied between DLL boundaries");
delete info;
}
- 对于
Info __stdcall GetInfo(InfoProvider* infoProvider)
你应该写一个包装器:
extern "C" __declspec( dllexport )
void __stdcall GetInfo(InfoProvider* infoProvider, Info* info)
{
static_assert(std::is_pod<Info>::value, "Must be Plain Old Data in order to be safely copied between DLL boundaries");
Info infoProvider = GetInfo(infoProvider);
info->data1 = infoProvider.data1;
info->data2 = infoProvider.data2;
}
我使用 Visual Studio 2017 编译了以下 C++ 方法:
extern "C" __declspec( dllexport )
Info* __stdcall GetInfo(InfoProvider* infoProvider)
{
static_assert(std::is_pod<Info>::value, "Must be Plain Old Data in order to be safely copied between DLL boundaries");
Info info = new Info();
Info->data1 = infoProvider->data1;
Info->data2 = infoProvider->data2;
return info;
}
在 Java 代码中,它由 Java 本机运行时使用具有以下签名的接口方法映射:
Info GetInfo(Pointer infoProvider);
final class Info extends Struct {
public final Signed32 data1;
public final Signed32 data2;
public R2VInfo(final Runtime runtime) {
super(runtime);
data1 = new Signed32();
data2 = new Signed32();
}
}
有效。
上面的C++方法导致内存泄漏,所以我想把它改成return result by value:
extern "C" __declspec( dllexport )
Info __stdcall GetInfo(InfoProvider* infoProvider)
{
static_assert(std::is_pod<Info>::value, "Must be Plain Old Data in order to be safely copied between DLL boundaries");
Info info{};
Info.data1 = infoProvider->data1;
Info.data2 = infoProvider->data2;
return info;
}
我使用相同的 Java JNR 映射:
Info GetInfo(Pointer infoProvider);
但它不起作用 - 访问冲突。调用本机方法,但有一些未处理的指针值。
如何在 JNR 中按值 return?
JNI 围绕旧的纯 K&R C 构建,以与所有可用的编译器兼容。从函数返回结构是在 C89 中引入的,并且在很晚的时候与 C++ 标准一起完全实现。今天,仍然可以在许多 java-friendly 环境(例如小型设备或 sim-cards)中找到这样的旧 C 编译器。所以我不认为JNI会升级到C89甚至C99。
对于您的情况,我建议编写一个额外的 C-code 来处理库函数的调用。代码可以通过两种方式实现:
- 对于
Info* __stdcall GetInfo(InfoProvider* infoProvider)
你应该这样写 free-function:
extern "C" __declspec( dllexport )
void __stdcall FreeInfo(Info* info)
{
static_assert(std::is_pod<Info>::value, "Must be Plain Old Data in order to be safely copied between DLL boundaries");
delete info;
}
- 对于
Info __stdcall GetInfo(InfoProvider* infoProvider)
你应该写一个包装器:
extern "C" __declspec( dllexport )
void __stdcall GetInfo(InfoProvider* infoProvider, Info* info)
{
static_assert(std::is_pod<Info>::value, "Must be Plain Old Data in order to be safely copied between DLL boundaries");
Info infoProvider = GetInfo(infoProvider);
info->data1 = infoProvider.data1;
info->data2 = infoProvider.data2;
}