6

我正在编写一个 JNI 程序,其中我的 .cpp 文件获取一个 jbyteArray,并且我希望能够使用 printf 打印 jbyteArray。为此,我相信我必须将 jbyteArray 转换为字符数组。

对于背景知识,我的 JNI 的 java 端将 String 转换为 byteArray,然后将该 byteArray 作为参数传递给我的 JNI 函数。

到目前为止我所做的可以正确打印出字符串,但后面是垃圾字符,我不知道如何摆脱这些/如果我做错了什么。

这是字符串的内容:

dsa

以及打印到控制台的内容:

dsa,�

垃圾字符会根据字符串的内容而变化。这是相关的代码部分:

.java 文件:

public class tcr extends javax.swing.JFrame{

static{
    System.loadLibrary("tcr");
}

public native int print(byte file1[]);

    .....

    String filex1 = data1TextField.getText();//gets a filepath in the form of a String from a GUI jtextfield.
    byte file1[]= filex1.getBytes();//convert file path from string to byte array

        tcr t = new tcr();
        t.print(file1);
}

.cpp 代码:

JNIEXPORT jint JNICALL Java_tcr_print(JNIIEnv *env, jobject thisobj, jbyteArray file1){

    jboolean isCopy;
    jbyte* a = env->GetByteArrayElements(file1,&isCopy);
    char* b;
    b = (char*)a;
    printf("%s\n",b);
}

任何帮助,将不胜感激。

4

2 回答 2

8

看看你在做什么:

jbyte* a = env->GetByteArrayElements(file1,&isCopy);

a现在指向存储字符串字节内容的内存地址。假设该文件包含字符串“Hello world”。在 UTF-8 编码中,这将是:

48 65 6c 6c 6f 20 77 6f 72 6c 64

char* b = (char*)a;

b现在指向那个内存区域。它是一个 char 指针,因此您可能希望将其用作 C 字符串。但是,这行不通。C 字符串被定义为一些字节,以零字节结尾。现在向上看,你会看到这个字符串的末尾没有零字节。

printf("%s\n",b);

这里是。您将 char 指针传递给printfas%s它告诉printf它是一个 C 字符串。但是,它不是 C 字符串,但printf仍会尝试打印所有字符,直到达到零字节。因此,您所看到dsa的实际上是字节数组结束后内存中的字节,直到(巧合)零字节。您可以通过将字节复制到比字节数组长一个字节的缓冲区,然后将最后一个元素设置为零来解决此问题。

更新:

您可以创建更大的缓冲区并附加空字节,如下所示:

int textLength = strlen((const char*)a);
char* b = malloc(textLength + 1);
memcpy(b, a, textLength);
b[textLength] = '\0';

Nowb是一个有效的以 null 结尾的 C 字符串。另外,不要忘记调用ReleaseByteArrayElements. 您可以在memcpy通话后立即执行此操作。

于 2013-07-05T16:17:18.877 回答
2

jbyteArray 实际上是通过 JNI 传递 Java 字符串的一种非常好的方法。它允许您轻松地将字符串转换为您在 C++ 端使用的库和文件/设备所需的字符集和编码。

确保您了解“每个软件开发人员绝对、肯定必须了解 Unicode 和字符集的绝对最低要求(没有借口!)

Java String 使用 Unicode 字符集和 UTF-16 编码(具有平台相关的字节顺序)。

String.getBytes()转换为“平台的默认字符集”。因此,它对您需要的字符集和编码做出假设,以及如何处理不在目标字符集中的字符。如果您想显式控制这些东西,您可以使用其他 Java String.getBytes 重载或 Charset 方法。

在决定使用哪种字符集和编码时,请考虑 Unicode 作为 Java、.NET、VB 等中的主要字符串类型已经使用了几十年;在 Java 的编译器源文件中,...;一般在万维网。当然,您可能会受到要与之互操作的事物的限制。

现在,您面临的问题似乎是目标字符集缺少您的 Java 字符串所具有的字符并且正在使用替代字符,或者您使用的控制台没有正确显示它们。

显然,控制台(或任何带有 UI 的应用程序)必须选择一种字体来呈现字符。字体通常不支持 Unicode 中可用的百万代码点。您可能能够更改控制台的配置(或使用另一个)。例如,在 Windows 中,您可以使用 cmd.exe 或 ps (Windows PowerShell)。您可以在 Cmd.exe 窗口中更改字体并用于chcp更改字符集。

更新:

正如@main-- 指出的那样,如果您使用的函数需要在字符串中附加一个终止符,那么您必须提供它,通常是通过复制数组,因为 JVM 保留了数组的所有权。这是这种情况下行为的实际原因。但是,以上所有内容也都是相关的。

于 2013-07-05T16:08:55.163 回答