gpt4 book ai didi

java - 从 native 代码返回 `const char*` 并在 java 中获取 `String`

转载 作者:太空狗 更新时间:2023-10-29 20:02:00 26 4
gpt4 key购买 nike

我正在使用 JNA 将我的 C++ 代码与 java 连接起来。我有一个 native 函数,它将一个字符串作为输入并返回一个字符串作为输出。以下是该函数的 C++ 实现。

const char* decrypt(char* value){
std::string res = TripleDes::getInstance().decrypt(value);
std::cout<<res.c_str()<<"\n";
return res.c_str();
}

我正在使用 JNA 将此函数加载到一个简单的 java 程序中,并尝试从 java 中获取一个字符串。问题是,我从 java 中得到一个空字符串。以下是java代码:

interface NativeExample extends Library {
NativeExample ne = (NativeExample) Native.loadLibrary("foo", NativeExample.class);
String decrypt(String value);
}

public class Main{

public static void main(String[] args){

String decrypted = NativeExample.ne.decrypt("foo");
System.out.println(decrypted);

}
}

C++ 代码的打印值是完美的,但 Java 打印的是一个空字符串。我看过这个question但它为 JNI 提供了解决方案。我想使用 JNA 并返回一个字符串。我该怎么办?

我还尝试返回 JNA Pointer 类型并在其上调用了 getString() 方法。但是会打印出乱码,这在所有调用中都不相同。

我知道我在函数范围内返回一个悬空指针,它会在它到达 java 调用时被销毁。我想要一个简单的解决方案,我可以使用 JNA 将字符串从 C++ 代码返回到 Java。

JNA 文档中提到了它 here你应该在 java 中使用 String 作为 C/C++ 中相应的 const char*

最佳答案

Caninonos 的回答充分说明了问题。这里有两种不同的解决方案。

A) 动态分配一个字符串并提供释放它的函数

您将不得不以某种方式释放字符串,因此请正确执行。提供一个函数,它接受返回的指针并释放它。考虑使用 AutoCloseabletry-with-resources声明。

C++

char* decrypt(char* value) {
std::string res = TripleDes::getInstance().decrypt(value);
std::cout << res.c_str() << "\n";
return strndup(res.c_str(), res.size());
}

void free_decrypted_string(char* str) {
free(str);
}

Java

interface NativeExample extends Library {
NativeExample ne = (NativeExample) Native.loadLibrary("foo", NativeExample.class);

Pointer decrypt(String value);
void free_decrypted_string(Pointer str);
}

public class Main {
public static void main(String[] args) {
Pointer decrypted = NativeExample.ne.decrypt("foo");
System.out.println(decrypted.getString(0));
NativeExample.ne.free_decrypted_string(decrypted);
}
}

如果您选择使用 AutoClosable,您可以受益于自定义 PointerType JNA 允许您将其用作 Pointer 的几乎直接替代品。但是,由于您实际上只是得到结果,因此最好将 JNA 接口(interface)封装在处理释放的 Java“解密器”类中。 AutoClosable 更适合文件或进程句柄之类的东西。

interface NativeExample extends Library {
NativeExample ne = (NativeExample) Native.loadLibrary("foo", NativeExample.class);

FreeableString decrypt(String value);
void free_decrypted_string(FreeableString str);

class FreeableString extends PointerType implements AutoCloseable {
@Override
public void close() {
ne.free_decrypted_string(this);
}
public String getString() {
return this.getPointer().getString(0);
}
}
}

public class Main {
public static void main(String[] args) {
try (NativeExample.FreeableString decrypted = NativeExample.ne.decrypt("foo")) {
System.out.println(decrypted.getString());
}
}
}

B) 更改decrypt 函数以接受输出缓冲区

不必记住释放动态分配的字符串,您可以使用输出参数。理想情况下,您希望使用 size_t 而不是 int,但使用它在 JNA 中有点笨拙。如果您需要处理比 int max 更长的字符串,计算出 size_t

由于您使用的是三重 DES,它可能会应用填充,因此输出的大小可能与输入的长度不同。为了解决这个问题,如果缓冲区太小,函数会输出所需的大小。

请注意该函数写入无空终止符,因此请确保使用返回值。

C++

int decrypt(const char *value, char *output, int *output_size) {
std::string res = TripleDes::getInstance().decrypt(value);
std::cout << res.c_str() << "\n";

if (*output_size < res.size()) {
*output_size = res.size();
return 0;
}

size_t bytes_written = res.copy(output, *output_size);
return (int)bytes_written;
}

Java

interface NativeExample extends Library {
NativeExample ne = (NativeExample) Native.loadLibrary("foo", NativeExample.class);
int decrypt(String value, byte[] output, IntByReference outputBufferSize);
}

public class Main {
public static void main(String[] args) {
byte[] buffer = new byte[4096];
IntByReference bufferSize = new IntByReference(buffer.length);

int bytesWritten = NativeExample.ne.decrypt("foo", buffer, bufferSize);
if (bytesWritten == 0 && bufferSize.getValue() > buffer.length) {
// buffer was too small for decrypted output
buffer = new byte[bufferSize.getValue()];
bytesWritten = NativeExample.ne.decrypt("foo", buffer, bufferSize);
}

String decrypted = new String(buffer, 0, bytesWritten);
System.out.println(decrypted);
}
}

如果您始终知道输出的大小,则可以简化调用以忽略更新后的所需缓冲区大小,或者将其从 C++ 函数中完全删除。

关于java - 从 native 代码返回 `const char*` 并在 java 中获取 `String`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48267403/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com