ndkでCの構造体についてお願いします。

763 views
Skip to first unread message

ohisamallc

unread,
Sep 25, 2010, 11:47:08 PM9/25/10
to Android-Group-Japan
山形のohisamaです。
お世話様です。
javaで無くて、Cです。

ndkのサンプルのhellojniに下記コードを書きますと
コンパイルは通りますが、実行中に落ちます。
 cygwinでmainに書いて、x86で実行するとOKです。
 ndk r3でng
 ndk r4でng
 ndk r4bは入れてません。

jstring
Java_com_example_hellojni_HelloJni_stringFromJNI
( JNIEnv* env, jobject thiz )
{
__android_log_print(ANDROID_LOG_INFO, "jni", "ok");
typedef struct test2
{
int a;
int b;
long c;
}test2;
test2 * x42;
x42->a = 888;
__android_log_print(ANDROID_LOG_INFO, "jni", "ok");
return (*env)->NewStringUTF(env, "Hello from JNI !");
}
次のように、書き換えますと、実行されます。

 typedef struct test2
{
int a;
int b;
long c;
};
struct test2 test2;
strust test2 * x42=&test2;

お願いは、①で落ちないよう。LOCAL_CFLAGSの
オプションを教えて下さい。
-std -ansi -pedantic等やってますが、正解見つかりません。
ndkのcflagの内容とかの情報もお願いします。
embeddedな方、お願いします。

sahd

unread,
Sep 26, 2010, 12:07:45 AM9/26/10
to android-g...@googlegroups.com

こんにちは。sahdと申します。

構造体のポインタだけ宣言して、そのメンバに値を代入しているので、
大抵SIGSEGVが飛んでくるはずです。

2の方法では構造体の実体を宣言して、そこの実体の先頭アドレスを
ポインタに格納しているので、そのプロセスの領域であることが保証され、
正しく動作します。

ということだと思うのですが、間違っていたらスミマセン。

2010 9 26 12:51 "ohisamallc" <pen...@mui.biglobe.ne.jp>:

ohisamallc

unread,
Sep 26, 2010, 1:58:46 AM9/26/10
to android-g...@googlegroups.com
sahd様、早速のご指導ありがとうございます。

①は、cygwinで動きます。
無理やり、理解すると
typedef struct test2
{
...
}test2;    <---ここで、構造体の確保。
test2 * x42; <---ここで、アドレスの取得。

こんなコード、gccの方言だと思いますが、なぜ
ndkでは、動かないのでしょう。
確かに、ndkでは、SIGSEGVで飛んでます。

        ohisama

--
このメールは Google グループのグループ「日本Androidの会」の登録者に送られて
います。
このグループに投稿するには、android-g...@googlegroups.com にメールを
送信してください。
このグループから退会するには、
android-group-j...@googlegroups.com にメールを送信してくださ
い。
詳細については、http://groups.google.com/group/android-group-japan?hl=ja
らこのグループにアクセスしてください。

tueda

unread,
Sep 26, 2010, 3:20:29 AM9/26/10
to android-g...@googlegroups.com, ohisamallc

> ①は、cygwinで動きます。
> 無理やり、理解すると
> typedef struct test2
> {
> ...
> }test2;    <---ここで、構造体の確保。
> test2 * x42; <---ここで、アドレスの取得。
>
> こんなコード、gccの方言だと思いますが、なぜ
> ndkでは、動かないのでしょう。
> 確かに、ndkでは、SIGSEGVで飛んでます。
>
>

SIGSEGVで落ちるのが正しい動作です。
cygwinで動いた(ように見える)のは偶然でしょう。
NDKとか何も関係ありません。
ポインター(x42)が何も指してませんよ。


杉浦登

unread,
Sep 26, 2010, 3:48:23 AM9/26/10
to android-g...@googlegroups.com
こんにちは

みなさんおっしゃるように、C言語的に間違えていて、
cygwinで動くのは偶然だと思います。

例えば普通のC言語で、
void main(void){
int *a;
*a=888;
}
とやるとエラーになります。
ポインタはメモリの場所(アドレス)を示すものですが、
この状況ではメモリの場所が決まっていないです。


私なら末尾のように書きます。
最初にmallocでメモリを確保して、
関数を抜ける前にfreeします。

その他細かい点としては
typedef struct宣言の使い方がちょっと?という感じ
でしたので少し書き換えまいた。
(問題ないのかもしれませんが)


typedef struct 
{
long   c;
int    a;
int    b;
}TEST2;
TEST2 * x42;

//メモリ確保
x42 = (TEST2 *)malloc (sizeof(TEST2));

//処理
x42->a   = 888;

//終了
free(x42);




2010年9月26日16:20 tueda <tu...@wolf.dog.cx>:

tm sute

unread,
Sep 26, 2010, 5:24:35 AM9/26/10
to android-g...@googlegroups.com
tmsuteです。

(10/9/26 14:58), ohisamallc wrote:
> ①は、cygwinで動きます。
> 無理やり、理解すると
> typedef struct test2
> {
> ...
> }test2;    <---ここで、構造体の確保。

別件ですが、構造体型名と、変数名が同一なので、たとえ
許されようとも書くべきではないでしょう。

> こんなコード、gccの方言だと思いますが、なぜ
> ndkでは、動かないのでしょう。

別に方言はないように思います。

heapをoverrunするとOSにすぐに殺されることが多いですが、
今壊しているのはstack領域上なので、殺されないことがあります。

もっと派手に壊すと、死ねると思います。

sahd

unread,
Sep 26, 2010, 11:44:02 AM9/26/10
to 日本Androidの会
こんばんは。sahdです。

普段構造体の定義はヘッダファイルに書く人間なので、細かい解釈は
よくわからないんですが、概ね他のみなさんのおっしゃるとおりです。

> test2 * x42; <---ここで、アドレスの取得。

これはただ単に4バイト(32ビット環境の場合)の変数を宣言しているだけで、
自動変数は宣言時に勝手に初期値が入ることもないので、この変数の中身は
「不定」
です。不定の具体値がいくつなのかはprintfで%pでx42を出してみないとわかりません。

で、Cygwinで落ちないのは、ここに入っている不定の値にアクセスしたとき
に、
->aした時に、x42の先頭アドレス(不定値)から5バイト先が、そのプロセスに
割り当てられているから。くらいしか理由が思いつきません。
#Cygwinでも-mno-cygwinとかしない限りはSEGVは飛びます。

というかですね、構造体を引数でポインタでもらってくるとかでなければ、
test2 * x42;
x42->a = 888;
ではなく、
test2 x42;
x42.a = 888;
にするのが一般的ではないかと思うんですが。
(わざわざポインタ使ってmallocなりnewしたらスコープ抜けるまでに
freeなりdeleteでヒープ開放しないといけないし。。
mallocとかnewの戻りでENOMEMチェックしないといけないし。。)

と感じていました。
> 2010 9 26 12:51 "ohisamallc" <peng...@mui.biglobe.ne.jp>:

sahd

unread,
Sep 26, 2010, 11:49:47 AM9/26/10
to 日本Androidの会
すみません、自己レスです。

tmsuteさんもおっしゃっている通り、SEGVが飛ばずに動くということは、
スタックのどこかに代入した888が上書かれているはずで、
次にその値を参照してしまった場合には原因不明なバグになる元になりますので
気をつけたほうがいいです。

amag

unread,
Sep 26, 2010, 11:00:02 AM9/26/10
to android-g...@googlegroups.com
amag です。

おそらく核心部分が質問者さんに伝わっていないのかもしれません。

  『新しい構造体型の宣言はしているが、変数宣言がなされていない』

ということです。

> typedef struct test2  ←ここでは「構造体タグ名」が定義される
> {
> ...
> }test2;    ←ここでは typedef による新しい「型」が定義される

上の記述は「構造体タグ名」と「型」がたまたま同じ test2 という名前で定義されただけであり、
「変数」は宣言されていません。つまり test2 という領域は確保されていないということです。
通常、構造体タグ名は必要ありません。構造体定義の内部に自分自身へのポインタを含む等のケースで必要になる程度です。
敢えて構造体タグ名も使うのであれば tagTest2 のように定義する型名とは明確に区別すべきでしょう。

typedef struct tagTest2 {
...
} Test2;

----------------
で、肝心の変数宣言です。

◆ 構造体タグ名を使うなら
struct tagTest2 t2;
struct tagTest2 *x42;

◆ typedef で定義した型名を使うなら
Test2 t2;
Test2 *x42;

----------------
私だったらこう書く、という例です。
typedef struct {
...
} Test2;
Test2 t2, *x42;
x42 = &t2;
 ・
 ・
 ・
※ ポインタへの代入を変数宣言と分けているあたりはC屋の古いスタイルかもしれません・・・気にしないでください(笑)

ohisamallc

unread,
Sep 26, 2010, 9:12:16 PM9/26/10
to android-g...@googlegroups.com
お世話様です。
山形のohisamaです。

反論は、次の点だけです。
 }test2; <--変数を同時に指定してると、思います。

確かにコードは、間違っていると思いますが、
結果が違うことに着目してます。

gcc 4.3.4(cygwin) 動く
gcc 4.2.1(ndk r4) 値は取れるがその後落ちる
gcc 4.4.0(ndk r4) 落ちる

結論は、gcc 4.3.4とgcc 4.2.1の挙動はおかしい。(偶然?)
成果は、gccの-mandoroidオプションを知りました。
皆さん、ご指導ありがとうございます。

> -----Original Message-----
> From: android-g...@googlegroups.com
> [mailto:android-g...@googlegroups.com]On Behalf Of amag
> Sent: Monday, September 27, 2010 12:00 AM
> To: android-g...@googlegroups.com

ohisamallc

unread,
Sep 27, 2010, 2:50:45 AM9/27/10
to android-g...@googlegroups.com
お世話様です。
山形のohisamaです。
自己スレです。
反論、しません。間違いでした、typedefです、型の指定です。
もまいしてます。はい。

tm sute

unread,
Sep 27, 2010, 11:21:06 AM9/27/10
to android-g...@googlegroups.com
tmsuteです。

あ"っ。

(10/9/27 0:00), amag wrote:
>> }test2;    ←ここでは typedef による新しい「型」が定義される

amagさんの指摘は正しいと私も思います。

私はtypedefを無視して、変数宣言だと解釈してしまいました。
これは誤った解釈でした。

#C++だと、もうtypedef struct...はほとんど書かないんですよねぇ。。
#言い分けになってない上に、もはや場違いの話題ですね。失礼しました。

Reply all
Reply to author
Forward
0 new messages