K.Maebashi's BBS

ご自由に書き込んでください。雑談も可。
テスト書き込みの類はテスト用掲示板にどうぞ

[日付順表示] [日付順インデックス] [スレッド順インデックス]

新規投稿 | 開設者ホームページへ戻る | ヘルプ

[1739] ローカル変数のアドレスをスタックにpushしている?
投稿者:とも
2011/09/10 21:18:23

始めて投稿します。 趣味で、オリジナルの言語を作成している途中です。 「プログラミング言語を作る」を大いに参考にさせて頂いています。 というより、かなりまねをさせてもらってます。 その中で気になるところがあり、投稿しました。 私自身はC言語をそれなりに習得しているつもりなのですが、誤解があったらご指摘下さい。 気になったのは、書籍の163ページの下部から165ページにわたる、eval_method_call_expression関数の例です。 eval系では、似たようなコードがいくつかあると思います。 関数の初頭で、resultというCRB_Value型の変数を宣言していますね。 式の評価結果をそれに詰め、最終的にcrowbarスタックにそのアドレスをpushしていると思います。 しかし、resultはローカル変数なので、関数を抜けるとその領域は既に使えないのではないか?という心配です。 Cでは関数の戻り値としてローカル変数のアドレスを返そうとすると警告が出ると思います。 書籍の例は、関数の戻り値として返しているわけではないので警告は出ないとは思います。 が、crowbarスタックにpushするということは、後からそれを使用する可能性があると思うのですが。 つまり次のプログラムと本質的には同じ事をしているように思えます。 ---------------------------------------------- #include <stdio.h> typedef struct { int type; char* data; } CRB_Value; CRB_Value *value; void eval_method_call_expression(){ CRB_Value result; result.type = 10; result.data = "Hello!"; value = &result; } int main(){ eval_method_call_expression(); printf("%d\n", value->type); printf("%s\n", value->data); } ---------------------------------------------- コンパイルではエラーも警告も出ないですが、上のプログラムはもちろん不正です。 既に議論済みだったら申し訳ありません。 はたまた、私がとんでもない勘違いをしているかもしれません。 御教示をお願いいたします。
[この投稿を含むスレッドを表示] [この投稿を削除]
[1740] Re:ローカル変数のアドレスをスタックにpushしている?
投稿者:(ぱ)こと管理人
2011/09/11 03:00:48

こんにちは。ご意見ありがとうございます。 >「プログラミング言語を作る」を大いに参考にさせて頂いています。 >というより、かなりまねをさせてもらってます。 そういっていただけると私も嬉しいです。 >関数の初頭で、resultというCRB_Value型の変数を宣言していますね。 >式の評価結果をそれに詰め、最終的にcrowbarスタックにそのアドレスをpushしていると思います。 >しかし、resultはローカル変数なので、関数を抜けるとその領域は既に使えないのではないか?という心配です。 ・resultはローカル変数なので、関数を抜けるとその領域は使えません。 ・最終的にcrowbarスタックにresultをpush()する際は、以下のような処理を  行っています。 push_value(inter, &result); ・resultのポインタをpush_value()に渡したって、resultの領域は  すぐに開放されてしまうのだから役に立たないのではないか? というのが  ご懸念されていることだと思います。 しかし、push_value()の中では、最終的には以下のようにして値をcrowbarスタックに 格納しています。 static void push_value(CRB_Interpreter *inter, CRB_Value *value) { (中略) inter->stack.stack[inter->stack.stack_pointer] = *value; 渡されたCRB_Valueは確かにポインタですが、*演算子により 「ポインタの指す先の値」をコピーしてスタックに格納していますので、 この後でresultが開放されても問題ありません。 なお、push_value()の引数として、CRB_Value*ではなくCRB_Valueを受け取るように することはもちろん可能です。 現状の実装でなぜポインタを渡しているのかというと…… 構造体は大きいかも しれないので値渡しをすると効率上の問題が出るかも、という懸念があったのかと 思います。実際問題としては、CRB_Value程度のサイズの型なら値渡しにするという 選択肢は十分考えられると思うのですけれども。
[この投稿を含むスレッドを表示] [この投稿を削除]
[1741] Re:ローカル変数のアドレスをスタックにpushしている?
投稿者:とも
2011/09/11 11:34:04

早速のお返事ありがとうございます。 なるほど、crowbarスタックの構造を勘違いしてました。 Stack構造体のstackメンバがCRB_Value*型だということは、"CRB_Value*"の集合ではなく、"CRB_Value"そのものの集合だということですね。 自分で作成中のものが、スタックを"アドレスの集合"にしているので、それと同じだと思い込んでいました。 参考になりました。 これからも、「プログラミング言語を作る」を参考にオリジナル言語の作成を続けたいと思います。 >こんにちは。ご意見ありがとうございます。 > >>「プログラミング言語を作る」を大いに参考にさせて頂いています。 >>というより、かなりまねをさせてもらってます。 > >そういっていただけると私も嬉しいです。 > >>関数の初頭で、resultというCRB_Value型の変数を宣言していますね。 >>式の評価結果をそれに詰め、最終的にcrowbarスタックにそのアドレスをpushしていると思います。 >>しかし、resultはローカル変数なので、関数を抜けるとその領域は既に使えないのではないか?という心配です。 > >・resultはローカル変数なので、関数を抜けるとその領域は使えません。 >・最終的にcrowbarスタックにresultをpush()する際は、以下のような処理を > 行っています。 > push_value(inter, &result); >・resultのポインタをpush_value()に渡したって、resultの領域は > すぐに開放されてしまうのだから役に立たないのではないか? というのが > ご懸念されていることだと思います。 > >しかし、push_value()の中では、最終的には以下のようにして値をcrowbarスタックに >格納しています。 > >static void >push_value(CRB_Interpreter *inter, CRB_Value *value) >{ >(中略) > inter->stack.stack[inter->stack.stack_pointer] = *value; > >渡されたCRB_Valueは確かにポインタですが、*演算子により >「ポインタの指す先の値」をコピーしてスタックに格納していますので、 >この後でresultが開放されても問題ありません。 > >なお、push_value()の引数として、CRB_Value*ではなくCRB_Valueを受け取るように >することはもちろん可能です。 >現状の実装でなぜポインタを渡しているのかというと…… 構造体は大きいかも >しれないので値渡しをすると効率上の問題が出るかも、という懸念があったのかと >思います。実際問題としては、CRB_Value程度のサイズの型なら値渡しにするという >選択肢は十分考えられると思うのですけれども。
[この投稿を含むスレッドを表示] [この投稿を削除]