在 JNI 函数 FindClass 的文档中,我可以阅读有关参数 name 的信息:
name: a fully-qualified class name (...) The string is encoded in modified UTF-8.
根据文档,修改后的 UTF-8 必须以双“\0”字符结尾:
the null character (char)0 is encoded using the two-byte format rather than the one-byte format
这是否意味着我应该以这种方式从 C 中调用 FindClass:
FindClass("java/lang/String\0")
即末尾有双'\0'?
最佳答案
字符集、编码和终止是三个不同的东西。显然,编码是为特定的字符集设计的,但是字符集可以用多种方式进行编码。而且,终止符(如果使用的话)通常是一个编码字符,但对于修改后的 UTF-8,情况并非如此。
Java 使用 Unicode 字符集。对于字符串和字符类型,它使用 UTF-16 编码。字符串类型统计;它不使用终止符。
在C语言中,常见的有终止字符串,以及各种字符集的单字节编码。 C 和 C++ 编译器以 NUL 字符终止文字字符串。在编译器的目标字符集编码中,这是一个或两个 0x00 字节。对于非控制 ASCII 字符,几乎所有常见字符集及其编码都具有相同的字节表示。 Unicode 字符集的 UTF-8 编码也是如此。 (但是,请注意,对于有限子集之外的字符,情况并非如此。)
JNI 设计者选择在 C 字符串之间使用这种有限的“互操作性”。许多 JNI 函数接受以 0x00 结尾的修改 UTF-8 字符串。这些与 C 编译器从源代码中的文字字符串生成的内容兼容,同样前提是字符限于非控制 ASCII 字符。这涵盖了在 JNI 中编写 Java 包和类、方法和字段字符串的用例。 (好吧,差不多:Java 允许在标识符中使用任何 Unicode 货币符号。)
因此,您可以以所见即所得的方式将 C 字符串文字传递给 JNI 函数。无需添加终止符——编译器会这样做。C 编译器会将额外的“\0”字符编码为 0x00,因此它不会造成任何伤害,但不是必需的。
标准 UTF-8 编码有一些修改。一种是允许期望 0x00 终止符的 C 函数“处理”修改后的 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 String
和 Charset
类在 C 函数设计的字符集和编码之间相互转换更为直接。通常,系统设置、用户设置、应用程序设置或线程设置决定了使用哪个 C 函数。 Java String
类在没有为转换指定特定编码时会尝试符合此类设置。但是,在很多情况下,所需的编码是固定的,可以明确指定。
关于java - JNI 字符串和 C 字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18311977/