Return 从 JNI (C++) 代码到 Java 的字符串

Return a string from JNI (C++) code to Java

Java代码:

public class MainClass 
{       
    static
    {
        System.load("/home/chronic/workspace/ramRead/src/libRamRead.so");
    }
    private native String readRam(int len, long addr, int pid);
    private native int readSize();

    public static void main(String[] args) 
    {
        MainClass app = new MainClass();


        String x = app.readRam(4096, 0x55c5520b5000L, 4435);

        //System.out.println("HEY THERE");
        //  System.out.println("I BEGIN HERE");
        System.out.println(x.length());

        //int test = app.readSize();
        //System.out.println(test);
    }
}

这是我的原生函数 (C++)

JNIEXPORT jstring JNICALL Java_ramRead_MainClass_readRam
  (JNIEnv *env, jobject, jint len, jlong addr, jint pid)
{
        struct iovec local[1];
        struct iovec remote[1];
        char buf[len];
        jstring result;
        //jcharArray buf = (*env).NewCharArray(len);
        //jcharArray buf1 = (*env).NewCharArray(len);

        local[0].iov_base = buf;
        local[0].iov_len = len;

        remote[0].iov_base = (void *) addr;
        remote[0].iov_len = len;

        nread = process_vm_readv(pid, local, 1, remote, 1, 0);

        //printf("len %d, pid %d, addr %li, buf %c, size of buf %d ", len, pid, addr, buf, sizeof(buf));
        printf("\nTHIS MUCH: %d\n", nread);

        for(int i=0; i<4096; i++){
                printf("%c", buf[i]);
        }

        //(*env).SetCharArrayRegion(buf1, 0, len, buf);
 result = (*env).NewStringUTF(buf);
        //printf("RESULT: %s", (*env).GetStringUTFLength(result));

        return result;
}

我的目标:

让C++中的native函数读取ram的内容,然后return将其作为字符串或char数组java进行进一步处理。

问题:

jstring result 的 return 值不是我在 java 中预期的值,有几个问题,首先它的长度是 7 而不是4096 正如预期的那样。另一个问题是输出是荒谬的。我有另一个用 C++ 编写的程序,它基本上读取 RAM 的内容,然后将它们打印到控制台。这是下面的代码,它的工作方式就像 charm.I 知道从哪个地址读取,我知道期望得到什么结果,只要我使用 C++,它就可以正常工作,但只要我将 JNI 与同样的方法出现前面提到的问题。

    #include <jni.h>
#include "ramRead_MainClass.h"
#include <sys/uio.h>

static ssize_t nread;

JNIEXPORT jbyteArray JNICALL Java_ramRead_MainClass_readRam
  (JNIEnv *env, jobject, jint len, jlong addr, jint pid)
//JNIEXPORT jbyteArray JNICALL Java_ramRead_MainClass_readRam
  //(JNIEnv *env, jobject, jobject len, jobject addr, jint pid)
{
        struct iovec local[1];
        struct iovec remote[1];
        jbyte buf[len];
        jbyteArray buf1 = (*env).NewByteArray(len);

        local[0].iov_base = buf;
        local[0].iov_len = len;

        remote[0].iov_base = (void *) addr;
        remote[0].iov_len = len;

        nread = process_vm_readv(pid, local, 1, remote, 1, 0);

        (*env).SetByteArrayRegion(buf1, 0, len, buf);
        return buf1;
}

JNIEXPORT jint JNICALL Java_ramRead_MainClass_readSize
  (JNIEnv *, jobject)
{
        return nread;
}

到目前为止我尝试过的:

检查清单 1.不是权限问题 2. ram地址是正确的,我知道那里存储了什么。我怎么知道? 我正在读取计算器的 RAM,我正在寻找我输入的一组特定数字。使用 C++,我找到了它们,但使用 jni 却找不到。 3. 阅读更多关于 UTF_8 和 UTF_16 的内容(很有可能问题出在这里) 4. 看到这里的帖子尝试重现解决方案,但没有成功。

OS: Linux 64 位 Fedora

问题:

如何将 C++ 字符串转换为 jstring,然后在 java 中 return 并打印出来,以便输出与上面列出的 C++ 程序的输出相匹配。

无论如何,这就是我打算解决它的方式,但如果有人有更好的解决方案或功能性解决方案,我会更乐意接受。

那么请大家付出时间和精力。

JNI 将字符串存储在 modified utf-8 encoding 中(见页面底部)。

如果您想继续使用字符串,则必须将您的字节转换为这种修改后的 utf-8 编码(因此字节值 >127 和零必须转换为 2 个字节)。

但正如 Jorn 在评论中建议的那样,您需要使用 ByteBuffer 或简单的字节数组 (byte[]),因为它更优化:使用 String ,你浪费内存,因为它包含 16 位元素。

我设法让它工作,但需要一些修补。这是下面的代码,可以与我发布的原始代码结合使用 非常感谢大家,我会尽量给答案投票。

在 Java 代码的主要内部,只需创建它即可将字节数组转换为人类可读的字符。主题演讲,并非所有字符都会被正确转换,但就我的测试而言,所有特殊字符都可以,例如!”£$%^&*()_+=-{}[]@~:;'#<>?,。 / 将打印出没有问题加上字母和数字 A-Z a-z 0-9 任何其他如果你有一些英文字母表之外的字母或类似的东西,你可能会遇到问题。

public static void main(String[] args){
        MainClass app = new MainClass();

            byte[] x = app.readRam(4096, 0x556cbdb2a000L, 22444);

            System.out.println(x.length);
            System.out.write(x, 0, x.length);

            for(int i=0; i<x.length; i++)
            {   
                if((int)x[i] >= 32 && (int)x[i] < 127)
                {
                    System.out.print((char)x[i]);
                }
            }

            char c = 120;
            System.out.println("\n" + c);

    }