【问题标题】:Passing a List of Strings from Java to C将字符串列表从 Java 传递到 C
【发布时间】:2012-10-06 03:20:01
【问题描述】:

我需要通过 JNI 将字符串列表从 Java 传递到 C。 我的 Java 程序传递一个 List 参数,而 C 程序接受一个列表。

下面是我试过的代码。

JNIEXPORT jobject JNICALL Java_jni_CallJNIfunction(JNIEnv *env,  
                                                         jobjectArray jParameters){

    list<const char*> cParameters;

    jsize stringCount = env->GetArrayLength(jParameters);

    for (int i=0; i<stringCount; i++) {
       jstring arrElement = (jstring) (env->GetObjectArrayElement(jParameters, i));
       const char* nativeElement = env->GetStringUTFChars( arrElement, NULL);

       cParameters.push_back(nativeElement);
       env->ReleaseStringUTFChars(arrElement, nativeElement);
    }

    CallCfunction(cParameters);

}

但是我的 JVM 在 GetStringUTFChars() 行崩溃了。 这个程序有什么问题?

【问题讨论】:

  • 当你说你传递了一个List的参数时,你真的是指一个数组吗? C 函数似乎是为了接受一个数组而编写的,如果 Java 传递一个 List 对象,您可以预期它会在某个时候崩溃。

标签: java c eclipse list java-native-interface


【解决方案1】:

你这样做:

const char* nativeElement = env->GetStringUTFChars( arrElement, NULL);
cParameters.push_back( nativeElement );
env->ReleaseStringUTFChars(arrElement, nativeElement);

您将存储的字符串释放到列表中,因此您的列表包含很多错误的指针!

您必须将字符串复制到长时间分配的空间中,您可以在 std::string、char*+malloc 或使用它并忘记它的方法之间进行选择。

第三种解决方案的解释:

for( int i = 0; i < stringCount; ++i )
{
   jstring arrElement = (jstring) (env->GetObjectArrayElement(jParameters, i));
   const char* nativeElement = env->GetStringUTFChars( arrElement, NULL);
   CallCfunction( nativeElement ); // modified to process an item not a list<
   env->ReleaseStringUTFChars(arrElement, nativeElement);
}

【讨论】:

    【解决方案2】:

    以下代码将采用Set&lt;String&gt; 并将其转换为std::vector&lt;std::string&gt;,但我不会这样做,您最好使用@ 上的toArray 方法将集合转换为数组987654324@,然后您就可以使用您的原始代码了。

    JNIEXPORT jobject JNICALL Java_jni_CallJNIfunction(
      JNIEnv *env,
      jclass,
      jobject setObj) {
    
        jmethodID iteratorID = env->GetMethodID(env->FindClass("java/util/Set"), "iterator", "()Ljava/util/Iterator;");
        jclass iterator = env->FindClass("java/util/Iterator");
        jmethodID hasNextID = env->GetMethodID(iterator, "hasNext", "()Z");
        jmethodID nextID = env->GetMethodID(iterator, "next", "()Ljava/lang/Object;");
    
        std::vector<std::string> strSet;
    
        jobject iteratorObj = env->CallObjectMethod(setObj, iteratorID);
        while (env->CallBooleanMethod(iteratorObj, hasNextID) == JNI_TRUE) {
          jstring current = (jstring)env->CallObjectMethod(iteratorObj, nextID);
          const char* str = env->GetStringUTFChars(current, NULL);
    
          strSet.push_back(str);
    
          env->ReleaseStringUTFChars(current, str);
        }
    }
    

    但除非你有大量的Set 复制到数组会太慢或占用太多内存,否则我会转换为数组。

    【讨论】:

      【解决方案3】:

      简单的 C 函数中的第一个答案是:

      char **GetStringsfromJniStringArray(JNIEnv *env, jobjectArray stringArray) {
          size_t stringCount = (size_t)(*env)->GetArrayLength(env, stringArray);
          char **Strings=calloc(stringCount, sizeof(char*));
          int i = 0;
          for(i = 0; i < (int)stringCount; ++i )
          {
              jstring jniString = (jstring) (*env)->GetObjectArrayElement(env, stringArray, i);
              const char *TempString = (*env)->GetStringUTFChars(env, jniString, NULL);
              Strings[i] = calloc(strlen(TempString)+1, sizeof(char));
              strcpy(Strings[i], TempString);
              (*env)->ReleaseStringUTFChars(env, jniString, TempString);
          }
          return Strings;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-12-11
        • 2012-07-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-20
        • 1970-01-01
        • 2014-02-04
        相关资源
        最近更新 更多