Java JNI:将多字节字符从java传递给c

时间:2014-02-26 22:15:59

标签: java c java-native-interface multibyte

我再一次搞乱java natve界面,我遇到了另一个有趣的问题。我通过jni向c发送文件路径,然后进行一些I / O.所以我遇到的最常见的问题是'äåö'。以下是具有完全相同问题的程序的简短演示:

爪哇:

public class java {

  private static native void printBytes(String text);
  static{
    System.loadLibrary("dll");
  }

  public static void main(String[] args){
    printBytes("C:/Users/ä-å-ö/Documents/Bla.txt");
  }
}

C:

#include "java.h"
#include <jni.h>

JNIEXPORT void JNICALL Java_java_printBytes(JNIEnv *env, jclass class, jstring text){
  const jbyte* text_input = (*env)->GetStringUTFChars(env, text, 0);
  jsize size = (*env)->GetStringUTFLength(env, text);
  int i = 0;
  printf("%s\n",text_input);
  (*env)->ReleaseStringUTFChars(env, text, text_input);
}

输出: C:/Users/├ñ-├Ñ-├Â/Documents/Bla.txt

这是 NOT 我想要的结果,我希望它输出与java中相同的字符串。

1 个答案:

答案 0 :(得分:3)

您正在处理特定于平台的字符编码问题。虽然标准的c printf应该能够处理多字节(utf-8)编码的字符串,但是windows / msvc提供的只是标准的而不是标准的。在非Windows标准符合平台上期望您的代码可以工作。来自java的字符串是UTF-8(多字节字符),MS printf期望ASCII(每个字符单字节)。这适用于ASCII字符,因为在UTF-8中,这些字符具有相同的值。它不适用于ASCII之外的字符。

基本上你需要将你的字符串转换为宽字符(text.getBytes(Charset.forName(UTF-16LE")))并将其作为数组从java传递给c,或者在收到它后将多字节字符串转换为c中的宽字符(MultiByteToWideChar(CP_UTF8, ...) )。然后你可以使用printf(“%S”)或wprintf(“%s”)来输出它。

有关详细信息,请参阅Printing UTF-8 strings with printf - wide vs. multibyte string literals。另请注意,如果您想在Windows控制台上输出unicode,则必须使用_setmode设置unicode输出模式。

另请注意,我不相信GetStringUTFLength保证NUL终止符,但它太长了。