JNI字符串和C字符串

时间:2013-08-19 10:49:53

标签: java c++ c java-native-interface

在JNI函数 FindClass 的文档中,我可以阅读有关参数 name 的信息:

  

name:完全限定的类名(...)字符串以修改后的UTF-8编码。

根据修改后的文件,UTF-8必须以双'\ 0'字符结尾:

  

空字符(char)0使用双字节格式而不是单字节格式

进行编码

这是否意味着我应该以这种方式从C调用FindClass: FindClass("java/lang/String\0")

即。在结尾加上'\ 0'?

3 个答案:

答案 0 :(得分:3)

不,according to the first reference I found,这意味着它应该像这样编码:

FindChar("java/lang/String\xc0\x80");
                              ^
                              |
                              |
                     This is not the shortest
                     way to encode the codepoint
                     U+0000, which is why it's
                     "modified" UTF-8.

请注意,这假设您确实在寻找名称以U + 0000结尾的类名,这是不太可能的。 C字符串应该像正常一样终止,只需要一个0字节:

FindChar("java/lang/String");

修改后的UTF-8提供的U + 0000的特殊双字节编码仅在您希望将U + 0000放入字符串时仍然很重要,并且仍然能够将其与C终止符区分开来。

答案 1 :(得分:3)

不,你没有编码终止零,它不是类名的一部分。

答案 2 :(得分:3)

字符集,编码和终止是三个不同的事情。显然,编码是针对特定字符集设计的,但字符集可以以多种方式编码。并且,通常,终结符(如果使用)是编码字符,但是使用修改后的UTF-8,情况并非如此。

Java使用Unicode字符集。对于字符串和字符类型,它使用UTF-16编码。字符串类型计算;它不使用终结器。

在C中,终止字符串是常见的,以及各种字符集的单字节编码。 C和C ++编译器使用NUL字符终止文字字符串。在编译器的目标字符集编码中,这是一个或两个0x00字节。几乎所有常见字符集及其编码都具有非控制ASCII字符的相同字节表示。对于Unicode字符集的UTF-8编码也是如此。 (但是,请注意,对于有限子集之外的字符,情况并非如此。)

JNI设计人员选择在C字符串之间使用这种有限的“互操作性”。许多JNI函数接受0x00终止的修改的 UTF-8字符串。这些兼容C编译器将从源代码中的文字字符串生成的内容,同样,前提是字符仅限于非控制ASCII字符。这包括编写Java包的用例。 JNI中的类,方法和字段字符串。 (好吧,差不多:Java允许在标识符中使用任何Unicode货币符号。)

因此,您可以以WYSIWYG样式将C字符串文字传递给JNI函数。无需添加终结符 - 编译器会这样做。 C编译器会将额外的'\ 0'字符编码为0x00,因此不会造成任何伤害,但不是必需的。

标准的UTF-8编码有一些修改。一种是允许C函数期望0x00终结符“处理”修改的UTF-8字符串,NUL字符(U + 00000)被编码以避免0x00,这将是标准。这允许将修改后的UTF-8字符串放入缓冲区,其中0x00终止符超出原始编码字符串的字节。另一个修改有点深奥,但这两个修改都使修改后的UTF-8字符串与严格兼容的UTF-8函数不兼容。

你没有问,但在JNI中还有另一种使用0x00终止,修改过的UTF-8字符串。它使用 GetStringUTFChars NewStringUTF 功能。 (JNI文档实际上并没有说GetStringUTFChars返回一个0x00终止的字符串,但没有已知的JVM实现没有。检查你的JVM实现者的文档或源代码。)这些函数设计在同一个“互操作性“基础。但是,用例不同,使它们变得危险。它们通常用于在C函数之间传递Java字符串。通常,C函数不知道修改的UTF-8是什么,或者甚至可能不知道UTF-8或Unicode是什么。使用Java StringCharset类来转换C语言函数的字符集和编码是更直接的。通常,系统设置,用户设置,应用程序设置或线程设置决定了C函数正在使用哪个。当没有为转换提供特定编码时,Java String类会尝试符合此类设置。但是,在许多情况下,所需的编码是固定的,可以明确指定。