【问题标题】:How do I convert jstring to wchar_t *如何将 jstring 转换为 wchar_t *
【发布时间】:2010-09-09 05:50:22
【问题描述】:

假设在 C++ 端,我的函数采用类型为 jstring 的变量,名为 myString。我可以将其转换为 ANSI 字符串,如下所示:

const char* ansiString = env->GetStringUTFChars(myString, 0);

有没有办法获得

const wchar_t* unicodeString = ...

【问题讨论】:

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


    【解决方案1】:

    这是我将jstring 转换为LPWSTR 的方法。

    const char* nativeString = env->GetStringUTFChars(javaString, 0);
    size_t size = strlen(nativeString) + 1;
    LPWSTR lpwstr = new wchar_t[size];
    size_t outSize;
    mbstowcs_s(&outSize, lpwstr, size, nativeString, size - 1);
    

    【讨论】:

      【解决方案2】:

      我尝试 jstring->char->wchar_t

      char* js2c(JNIEnv* env, jstring jstr)
      {
          char* rtn = NULL;
          jclass clsstring = env->FindClass("java/lang/String");
          jstring strencode = env->NewStringUTF("utf-8");
          jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
          jbyteArray barr = (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
          jsize alen = env->GetArrayLength(barr);
          jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
          if (alen > 0)
          {
              rtn = (char*)malloc(alen + 1);
              memcpy(rtn, ba, alen);
              rtn[alen] = 0;
          }
          env->ReleaseByteArrayElements(barr, ba, 0);
          return rtn;
      }
      
      jstring c2js(JNIEnv* env, const char* str) {
          jstring rtn = 0;
          int slen = strlen(str);
          unsigned short * buffer = 0;
          if (slen == 0)
              rtn = (env)->NewStringUTF(str);
          else {
              int length = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)str, slen, NULL, 0);
              buffer = (unsigned short *)malloc(length * 2 + 1);
              if (MultiByteToWideChar(CP_ACP, 0, (LPCSTR)str, slen, (LPWSTR)buffer, length) > 0)
                  rtn = (env)->NewString((jchar*)buffer, length);
              free(buffer);
          }
          return rtn;
      }
      
      
      
      jstring w2js(JNIEnv *env, wchar_t *src)
      {
          size_t len = wcslen(src) + 1;
          size_t converted = 0;
          char *dest;
          dest = (char*)malloc(len * sizeof(char));
          wcstombs_s(&converted, dest, len, src, _TRUNCATE);
      
          jstring dst = c2js(env, dest);
          return dst;
      }
      
      wchar_t *js2w(JNIEnv *env, jstring src) {
      
          char *dest = js2c(env, src);
          size_t len = strlen(dest) + 1;
          size_t converted = 0;
          wchar_t *dst;
          dst = (wchar_t*)malloc(len * sizeof(wchar_t));
          mbstowcs_s(&converted, dst, len, dest, _TRUNCATE);
          return dst;
      }
      

      【讨论】:

        【解决方案3】:

        如果这对某人有帮助...我已将此功能用于 Android 项目:

        std::wstring Java_To_WStr(JNIEnv *env, jstring string)
        {
            std::wstring value;
        
            const jchar *raw = env->GetStringChars(string, 0);
            jsize len = env->GetStringLength(string);
            const jchar *temp = raw;
            while (len > 0)
            {
                value += *(temp++);
                len--;
            }
            env->ReleaseStringChars(string, raw);
        
            return value;
        }
        

        改进的解决方案可能是(感谢您的反馈):

        std::wstring Java_To_WStr(JNIEnv *env, jstring string)
        {
            std::wstring value;
        
            const jchar *raw = env->GetStringChars(string, 0);
            jsize len = env->GetStringLength(string);
        
            value.assign(raw, raw + len);
        
            env->ReleaseStringChars(string, raw);
        
            return value;
        }
        

        【讨论】:

        • 整洁,尽管我怀疑一次性加载带有缓冲区的 wstring 会比一次一个字符更有效。
        • C++ 编译器是否注意到您正在返回一个自动值,并将其分配在堆上而不是堆栈上?
        【解决方案4】:

        我知道这是一年前问的,但我不喜欢其他答案,所以无论如何我都会回答。以下是我们在源代码中的做法:

        wchar_t * JavaToWSZ(JNIEnv* env, jstring string)
        {
            if (string == NULL)
                return NULL;
            int len = env->GetStringLength(string);
            const jchar* raw = env->GetStringChars(string, NULL);
            if (raw == NULL)
                return NULL;
        
            wchar_t* wsz = new wchar_t[len+1];
            memcpy(wsz, raw, len*2);
            wsz[len] = 0;
        
            env->ReleaseStringChars(string, raw);
        
            return wsz;
        }
        

        编辑:此解决方案适用于 wchar_t 为 2 字节的平台,某些平台具有 4 字节 wchar_t 在这种情况下此解决方案将不起作用。

        【讨论】:

        • 这个解决方案是错误的。因此,我吸了 12 个小时。 wchar_t 和 jchar 不必相同。证明是我的测试程序的输出:01-26 20:28:43.675: E/[LMI-NATIVE](9280): len: 7, jchar: 2, wchar: 4
        • @Kobor42 - 你的测试程序是做什么的?你是说你找到了一个 wchar_t 为 4 个字节的实例?我实际上并没有意识到这一点,但这个函数被设计为(主要)在 wchar_t 始终为 2 的 Windows 上运行。我现在意识到 wchar_t 是特定于编译器的,并且在您的平台上可能会有所不同。
        • 没错。在 Android 2.1 之前的版本中,wchar_t 为 1 个字节。 2.1 及之后是 4 个字节。
        • 您正在混合可能不兼容的类型。 Java jchar 始终是 UTF-16。但wchar_t 并不总是 UTF-16,有时是 UTF-32。在这种情况下,您需要将 UTF-16 转换为 UTF-32(这不仅仅是将 jchar 填充为 4 个字节的问题,有关详细信息,请参阅en.wikipedia.org/wiki/UTF-16)。
        • 我没有混合它。 NDK 正在混合它。我想将没有信息丢失的java字符串转换为c字符串。
        【解决方案5】:

        相当简单。但是不要忘记通过 ReleaseStringChars 释放内存

        JNIEXPORT jboolean JNICALL Java_TestClass_test(JNIEnv * env, jobject, jstring string)
        {
            const wchar_t * utf16 = (wchar_t *)env->GetStringChars(string, NULL);
            ...
            env->ReleaseStringChars(string, utf16);
        }
        

        【讨论】:

          【解决方案6】:

          谁释放 wsz? 我会推荐 STL!

          std::wstring JavaToWSZ(JNIEnv* env, jstring string)
          {
              std::wstring value;
              if (string == NULL) {
                  return value; // empty string
              }
              const jchar* raw = env->GetStringChars(string, NULL);
              if (raw != NULL) {
                  jsize len = env->GetStringLength(string);
                  value.assign(raw, len);
                  env->ReleaseStringChars(string, raw);
              }
              return value;
          }
          

          【讨论】:

          • 除非使用 C++11,否则这不是一个很好的解决方案,因为 wstring 将按值返回。 (显然在 C++11 之后,它将被移动构造,这将是有效的)
          • value.assign(raw, len);无效。我认为应该是 value.assign(raw, raw + len);但我还没有测试。
          • 太棒了 - 在 C# -> C++/CLI -> JNI -> Java 应用程序中完美地为我工作!
          • 无论GetStringChars是否成功,您都不必调用ReleaseStringChars,否则jstring可能会被固定并“泄漏”
          【解决方案7】:

          只需使用 env->GetStringChars(myString, 0); Java 传递 Unicode 的本质

          【讨论】:

            【解决方案8】:

            JNI 也有一个 GetStringChars() 函数。返回类型是 const jchar*,jchar 在 win32 上是 16 位的,因此在某种程度上与 wchar_t 兼容。不确定它是真正的 UTF-16 还是其他...

            【讨论】:

            • 你知道jchar 的字节顺序是否与Win32 wchar_t 兼容吗?应该是,但可以肯定的是。 :-)
            • jchar 的类型定义为无符号短。我自己没有尝试过,但我的猜测是“是”。
            • char == jchar == 无符号 16 位
            • char == unsigned 16 bits 在哪个平台上?
            • 为了避免混淆,在本次讨论中,“char”是 ISO C 和 C++ 语言中的内置数据类型,而不是 Java。
            【解决方案9】:

            一个可移植且强大的解决方案是使用iconv,但您必须知道您的系统wchar_t 使用什么编码(例如,在Windows 上使用UTF-16,在许多Unix 系统上使用UTF-32)。

            如果您想尽量减少对第三方代码的依赖,您还可以手动滚动您自己的 UTF-8 转换器。如果转换为 UTF-32,这很容易,但使用 UTF-16 会有些困难,因为您也必须处理代理对。 :-P 另外,您必须小心拒绝non-shortest 表单,否则在某些情况下会引发安全漏洞。

            【讨论】:

            • 您建议将 jstring 转换为 UTF-8,然后再转换回 UTF-16?真的有必要吗?
            • @Rup jstrings already UTF-8: "JNI 使用修改后的 UTF-8 字符串来表示各种字符串类型。修改后的 UTF-8 字符串与 Java VM 使用的相同。修改后的 UTF -8 字符串被编码,使得仅包含非空 ASCII 字符的字符序列可以仅使用每个字符一个字节来表示,但可以表示所有 Unicode 字符.....Java VM 不识别四字节格式标准的 UTF-8;它使用自己的两倍三字节格式来代替。"
            • @b1naryatr0phy 真的吗?我的系统(1.6 和 1.7)上的 jni.h 有 typedef unsigned short jchar;,在我看来更像是 UTF-16。
            • 那我一定是误会了,这句话是直接从 Oracle 的文档中提取的:http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/types.html 如果可以的话,请随意解释,我仍在努力解决这个问题。
            【解决方案10】:

            如果我们对跨平台能力不感兴趣,您可以在 windows 中使用 MultiByteToWideChar 函数,或有用的宏 A2W(参考 example)。

            【讨论】:

              猜你喜欢
              • 2021-11-17
              • 1970-01-01
              • 2012-05-16
              • 1970-01-01
              • 1970-01-01
              • 2018-01-07
              • 2011-03-14
              • 2021-01-29
              相关资源
              最近更新 更多