質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
JNI

JNI(Java Native Interface)は、Javaプラットフォームにおいて、Javaで記述されたプログラムと、他の言語で書かれたネイティブコードを連携するためのインタフェース仕様である

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Android NDK

Android NDKとは、Android SDKと対を成すツールです。ネイティブコードのアプリ、またはC/C++言語の既存のポートライブラリでパフォーマンスクリティカルな部分を構築できます。ヘッダ、ライブラリを提供して、アクティビティやユーザ入力処理などを構築できます。

Q&A

解決済

1回答

1587閲覧

JNIで配列を使う時に、配列が壊れてしまう

Wind

総合スコア442

JNI

JNI(Java Native Interface)は、Javaプラットフォームにおいて、Javaで記述されたプログラムと、他の言語で書かれたネイティブコードを連携するためのインタフェース仕様である

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Android NDK

Android NDKとは、Android SDKと対を成すツールです。ネイティブコードのアプリ、またはC/C++言語の既存のポートライブラリでパフォーマンスクリティカルな部分を構築できます。ヘッダ、ライブラリを提供して、アクティビティやユーザ入力処理などを構築できます。

0グッド

0クリップ

投稿2020/02/03 03:31

編集2020/02/03 07:53

前提・実現したいこと

AndroidStudioでJavaからJNIへint配列を渡して値を一つずつ使いたいのですが、ループを使用すると2回目から配列が壊れてしまいます。
ポインタや配列の使い方が間違っているのでしょうか?

発生している問題・エラーメッセージ

JNIでポインタから配列への値コピーで、ループの2回目以降は下記エラーになってしまいます。
read memory from 0x1 failed (0 of 4 bytes read)

再現可能なソースコード

プロジェクトの作成に従って作成し、Javaからint配列をJNIへ送る様に変更しました。

Java

1public class MainActivity extends AppCompatActivity { 2 static { 3 System.loadLibrary("native-lib"); 4 } 5 6 @Override 7 protected void onCreate(Bundle savedInstanceState) { 8 super.onCreate(savedInstanceState); 9 setContentView(R.layout.activity_main); 10 11 int[] intValues = new int[10]; 12 for(int i=0; i < 10; i++) 13 intValues[i] = i+1; // 1~10を入れる 14 15 TextView tv = findViewById(R.id.sample_text); 16 tv.setText(stringFromJNI(intValues)); 17 } 18 19 public native String stringFromJNI(int[] ints); 20} 21

JNI

1#include <jni.h> 2#include <string> 3 4extern "C" JNIEXPORT jstring JNICALL 5Java_s_glc_cpptestplus_MainActivity_stringFromJNI( 6 JNIEnv *env, 7 jobject /* this */, 8 jintArray intValues 9 ) { 10const jint intLength = env->GetArrayLength(intValues); 11 jint *intValuesCpp = env->GetIntArrayElements(intValues, 0); 12 13 int intDat[intLength]; 14// for(int i=0;i<intLength ;i++) 15// intDat[i] = 0; 16 17/* 18 intDat[0] = intValuesCpp[0]; 19 intDat[1] = intValuesCpp[1]; 20 intDat[2] = intValuesCpp[2]; 21 intDat[3] = intValuesCpp[3]; 22 intDat[4] = intValuesCpp[4]; 23 intDat[5] = intValuesCpp[5]; 24 intDat[6] = intValuesCpp[6]; 25 intDat[7] = intValuesCpp[7]; 26 intDat[8] = intValuesCpp[8]; 27 intDat[9] = intValuesCpp[9]; 28*/ 29 for(int i = 0;i < intLength;i++) 30 intDat[i] = intValuesCpp[i]; 31 32 std::string strValues = ""; 33 for(int i = 0;i < intLength;i++) 34 strValues += intDat[i]; 35 36 37 env->ReleaseIntArrayElements(intValues, intValuesCpp,false); 38 std::string hello = "Hello from C++" + strValues; 39 return env->NewStringUTF(hello.c_str()); 40}

app

1 buildTypes { 2 debug{ 3 debuggable true 4 minifyEnabled false 5 } 6 release { 7 minifyEnabled false 8 proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 9 } 10 } 11 externalNativeBuild { 12 cmake { 13 path "src/main/cpp/CMakeLists.txt" 14 version "3.10.2" 15 } 16 } 17} 18 19dependencies { 20 implementation fileTree(dir: 'libs', include: ['*.jar']) 21 implementation 'androidx.appcompat:appcompat:1.1.0' 22 implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 23 testImplementation 'junit:junit:4.13' 24 androidTestImplementation 'androidx.test.ext:junit:1.1.1' 25 androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 26}

試したこと

JNI

1 intDat[0] = intValuesCpp[0]; // intDat[0]に1が入る 2 intDat[1] = intValuesCpp[1]; // intDat配列が「parent failed to evaluate: variable not available」になる 3 intDat[2] = intValuesCpp[2]; 4 intDat[3] = intValuesCpp[3]; 5 intDat[4] = intValuesCpp[4]; 6 intDat[5] = intValuesCpp[5]; 7 intDat[6] = intValuesCpp[6]; 8 intDat[7] = intValuesCpp[7]; 9 intDat[8] = intValuesCpp[8]; 10 intDat[9] = intValuesCpp[9];

補足情報(FW/ツールのバージョンなど)

Windows10
AndroidStudio 3.5.3

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2020/02/03 05:32 編集

macOSでほぼ同等の環境(AndoidStudio 3.5.3)とコードで試しましたが、問題が再現しません。ただ、ご提示のコードではコンパイルエラーになります。 std::string strValues = ""; for(int i=0;i<intLengh;i++) で、intLenghがスペルミス(宣言されているのはintLength)です。本当にこのコードで試されているのでしょうか。
Wind

2020/02/03 05:47

動作確認と修正依頼ありがとうございます。 再現するコードを書いた後で元のコードでスペルミスに気づいたのですが、 こちらのコードのスペルミスを手書きで中途半端に修正したままでした。 動作確認したJNIコードに差し替えました。
guest

回答1

0

ベストアンサー

macOS用 AndroidStudio3.5.3、Androidバージョン4.4(KitKat)のエミュレータ上でいくつかのビルドのパターンを試してみましたが、問題を再現することができませんでした。Window用のAndroid Studio とはAndroid NDK用のtoolchainのC++コンパイラが違っているせいだと思われます。

エラーメッセージの内容から臭うのは可変長配列(VLA)を使用した以下の部分ですが、

C++

1 const jint intLength = env->GetArrayLength(intValues); 2 ... 3 int intDat[intLength];

この部分をstd::vectorに変えることで問題が発生しない、よりポータブルなコードになると思いますので試してみてください。「可変長配列(VLA)を利用した場合に問題が発生する」とのような報告は、Android Studioに限らず他のC++コンパイラでも散見します。

C++

1#include <jni.h> 2#include <string> 3#include <vector> 4 5extern "C" JNIEXPORT jstring JNICALL 6Java_s_glc_cpptestplus_MainActivity_stringFromJNI( 7 JNIEnv *env, 8 jobject /* this */, 9 jintArray intValues 10) { 11 const jint intLength = env->GetArrayLength(intValues); 12 jint *intValuesCpp = env->GetIntArrayElements(intValues, 0); 13 14 // 可変長配列(VLA/Variable Length Array)ではなく、std::vectorを使う。 15 //int intDat[intLength]; 16 std::vector<int> intDat(intLength); 17 for(int i = 0; i < intLength; i++) { 18 intDat[i] = intValuesCpp[i]; 19 } 20 21 std::string strValues; 22 for(int i = 0; i < intLength; i++) { 23 // strValues += intDat[i]; 24 strValues += std::to_string(intDat[i]) + ","; 25 } 26 27 env->ReleaseIntArrayElements(intValues, intValuesCpp, false); 28 std::string hello = "Hello from C++ : " + strValues; 29 return env->NewStringUTF(hello.c_str()); 30}

実行例です:
実行例

投稿2020/02/03 17:34

dodox86

総合スコア9256

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Wind

2020/02/04 00:38

問題が再現しないのに回答してくださり、本当にありがとうございます。 こちらはAndroid9.0と10の実機にて問題が発生しました。 int[]からstd::vectorに変えることで、正常に動作させることが出来ました。
dodox86

2020/02/04 01:20

> こちらはAndroid9.0と10の実機にて問題が発生しました。 気になったので追試してみました。Android 6.0.1の実機でも、Android 10のエミュレータ(x86)でも問題が再現しませんでした。Android 9以降の実機(armネイティブ)で起きる事象かもしれませんね。そうだと、なおさらtoolchain/C++コンパイラの違いも影響しそうです。
Wind

2020/02/04 02:49 編集

追試までして頂き、ありがとうございます。 こちらも再現性が気になりましたので、実機のPixel3(Android10)と同じPixel3 API29エミュレータ(x86)を使用してみたところ、エミュレータ上ではint[]でも動作しました。 今の所、Android9.0以降の実機でデバッグした方が良さそうですね。
kakajika

2020/02/04 03:46

この問題と関連しているかもしれませんね https://github.com/android/ndk/issues/781 NDKの古いバージョンをお使いなら、r19以上にアップデートすることで問題が解決するかもしれません。
dodox86

2020/02/04 04:39 編集

kakajikaさん、情報ありがとうございます。ndkのissuesは完全に見落としていました。私も参考にさせていただきます。尚、私の方でインストール済みのndkのバージョンは現時点で最新にUpdate済み、21.0.6113669 でした。(参考まで)
Wind

2020/02/04 04:45

情報ありがとうございます、こちらもNDK version=21.0.6113669です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問