• ベストアンサー

C言語 関数の戻り値と自動変数

かなり基礎的な質問になるのですが、疑問に思うことがあり、質問をさせていただきます。 関数内で宣言した変数を戻り値として使う場合ですが、ポインタなどではなく実体の場合でも、静的変数として宣言をしたほうが良いのでしょうか? 現実的に考えると、プログラムが関数から出て、呼び出した側の関数が戻り値を受け取るまでの瞬間に、その領域が書き換えられる可能性は極めて低いと思うのですけど、C言語の仕様としてはどうなのでしょうか? 関数内で宣言した戻り値に使う変数には、必ずstaticをつけた方が良いのでしょうか? もしおわかりでしたら教えて下さい。

質問者が選んだベストアンサー

  • ベストアンサー
  • 1839cc
  • ベストアンサー率54% (12/22)
回答No.7

> ちょっと難しく考えすぎちゃっていました。 いえ、とてもよい感覚をお持ちだと思います。 恐らく、「呼び出し元が戻り値を受ける前に、返したいローカル変数が消滅してしまうのではないか」という懸念をお持ちなのではないでしょうか。 だとすれば、お察しの通りです。 おそらく、多くのC言語およびC++言語のコンパイラは、そのようなコードを生成するでしょう。 けれど、安心してください。 そのようなコンパイラであったとしても、戻り値は暗黙的に一時変数に待避されていますので、呼び出し元は戻り値を安全に受けることができます。 つまり、static にする必要はありません。 ただ、一時変数にコピーされるということは、無駄なコピーが1回働くということを意味します。 ですので、大きな構造体などを戻り値に指定するのは避けたほうがよいでしょう。 大きな構造体を返したい場合は、構造体のポインタを引数で受け取るように心がけてください。 目安として、アドレスより大きな構造体は返さないことです。

tadasuke2002
質問者

お礼

そうなんです。 >呼び出し元が戻り値を受ける前に、返したいローカル変数が消滅してしまうのではないか と、考えてしまっていたんです。 もしくは消滅はしないまでも、他の変数などに使われてしまう可能性が絶対にないとはいえないのではないかと・・・ でも、一時変数にコピーされるのなら大丈夫なんですね。 しかも、戻り値に構造体を使わないほうが良い理由というのが初めてきちんとわかりました(^_^;) ご返答、ありがとうございます。

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (7)

回答No.8

> 現実的に考えると、プログラムが関数から出て、呼び出した側の関数が戻り値を受け取るまでの瞬間に、その領域が書き換えられる可能性は極めて低いと思うのですけど、C言語の仕様としてはどうなのでしょうか? この問題はマルチスレッドにしない限り起りません。 (厳密には他にもあると思いますが) > 関数内で宣言した戻り値に使う変数には、必ずstaticをつけた方が良いのでしょうか? 基本的にする必要はないと思いますが、 ケースバイケースだと思います。 個人的に必要がある思うケースは、 ある関数とあるデータの関係を密接にしたい場合は必要だと思います。 staticの変数を返す関数ではないですが string.h にある、strtokとstrtok_rの違いについて考えてみてください。 strtokは確実に、staticな変数を使っています。 (もしかするとスレッドローカル変数かもしれませんが)

tadasuke2002
質問者

お礼

マルチスレッドを考慮に入れていたわけではないので、基本的には心配する必要がないということですね。 いろいろと勉強になりました。 ご返答ありがとうございます。

全文を見る
すると、全ての回答が全文表示されます。
  • aris-wiz
  • ベストアンサー率38% (96/252)
回答No.6

>関数内で宣言した変数を戻り値として使う場合ですが、ポインタなどではなく実体の場合でも、静的変数として宣言をしたほうが良いのでしょうか? 変数であろうと、ポインタ変数であろうと、 関数内で宣言された自動変数は関数終了時に破棄されます。 関数内で宣言した変数のポインタを返却しそれ以外の関数でも使用する なら静的変数にする以外にありませんが、戻り値として C言語では式を持つreturn文を実行すると、その式の"値"を 関数呼び出し式の値として呼び出し側へ返すという決まりがあります。(C99) つまり ・値を返すならば自動変数で問題ない。  静的変数を返却する場合むしろマルチスレッド環境などでは、  バグになる可能性もある。 ・関数内で宣言した自動変数に値を入れ、その変数のポインタを  上位に返し使用する事はできない。 ・関数内で宣言した静的変数ならばそのポインタを返却し上位でも  使用することができるが、やはりマルチスレッド環境などでの  考慮は必要。 って感じの事が分かっていれば大丈夫かと。

tadasuke2002
質問者

お礼

値を返す場合は、自動変数で問題なかったんですね。 自分でもずっとそのつもりでいて、実際にそのようなソースを書いてきたのですが、自動変数についていろいろ勉強していたら、ふと疑問に感じてしまって(^_^;) ご返答、ありがとうございました。

全文を見る
すると、全ての回答が全文表示されます。
  • noocyte
  • ベストアンサー率58% (171/291)
回答No.5

マルチスレッド/マルチタスク環境での心配をしておられるのなら, むしろ戻り値を static 変数に入れる方が問題です. 関数内で変更する変数を static にしてしまうと, その関数はリエントラントでなくなりますし, static 変数の排他制御をしないのならスレッドセーフでもなくなります. リエントラント (Wikipedia) http://ja.wikipedia.org/wiki/%E3%83%AA%E3%82%A8%E3%83%B3%E3%83%88%E3%83%A9%E3%83%B3%E3%83%88 スレッドセーフ (Wikipedia) http://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%AC%E3%83%83%E3%83%89%E3%82%BB%E3%83%BC%E3%83%95

tadasuke2002
質問者

お礼

マルチスレッドのことまでを考慮しているわけではなかったんです。というより、そこまで考慮できるほどの熟練者でもないので(^_^;) 新しい用語もたくさん教えていただいたので、これから勉強してみます。 ご返答、ありがとうございました。

全文を見る
すると、全ての回答が全文表示されます。
  • ryopis
  • ベストアンサー率20% (49/238)
回答No.4

No,3です。 スタックに積まれるかどうかは処理系依存でした。。。 レジスタにおかれるのが普通でしょうか。

全文を見る
すると、全ての回答が全文表示されます。
  • ryopis
  • ベストアンサー率20% (49/238)
回答No.3

ポインタも実態は数値なので、ポインタでも変数でも同じコトです。 staticをつけると、マルチスレッドなど複数の実行主体がある場合に 動作が変わりますが、そうでない場合は、基本的に戻り値は スタックに積まれるので自動変数で問題ないかと。

tadasuke2002
質問者

お礼

マルチスレッドまで考えてのことではないのですが、自動変数だと、元の関数が値を受け取る前に消滅する可能性も0%ではないのでは・・・なんて、ちょっと難しく考えすぎちゃっていたみたいなんです。 ご返答、ありがとうございました。

全文を見る
すると、全ての回答が全文表示されます。
  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.2

>呼び出した側の関数が戻り値を受け取るまでの瞬間に、 >その領域が書き換えられる可能性 マルチスレッドのプログラムですか? 排他制御と static 変数には何の関係もないと思いますが。 変数を static と宣言することによって tadasuke200 さんが期待している効果を補足すると、アドバイスを得やすいでしょう。

tadasuke2002
質問者

お礼

マルチスレッドまで考えてのことではないのですが、例えば、free関数などで開放した領域をすぐに使用するとか、基本的には動くけどCの仕様としては間違っているというような状況なのかと考えたりしてしまいまして・・・ 難しく考えすぎました(^_^;) ご返答ありがとうございます。

全文を見る
すると、全ての回答が全文表示されます。
  • ymmasayan
  • ベストアンサー率30% (2593/8599)
回答No.1

return a*b なんていう戻り値も使えますから、staticとかautomaticとかは考える必要は無いですね。

tadasuke2002
質問者

お礼

やっぱりそうですよね。 ちょっと難しく考えすぎちゃっていました。 ご返答ありがとうございます。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • C言語 関数の戻り値について

    C言語で関数を作る場合に最後にreturnで戻り値を設定しますよね? 自分はあまりそれがわかりません。 関数で出た答えを返すって言うのはわかるんですが、 returnが無くても大丈夫だったりreturnはあってもその後に戻り値を設定していなかったり。 何故returnがなくても動作するのでしょうか? 何故returnまであるのに戻り値は設定されていないのか? 教えてください。

  • C言語のStatic変数について

    現在、C言語の勉強しながらゲームプログラムにチャレンジしています。 二つの関数で利用する変数を作りたかったので、Static宣言された変数を容易しました。 ですが、この変数、一度処理が終わると当面使わない変数なのです。 (ただし、処理途中は何度も呼び出されるので値は保持しなければいけません) よって、メモリ上に延々居座られるのが邪魔に思えて仕方ありません。 実際、大したことないだろうとは思うのですが。 このStaticで宣言された変数を、自分の好きなタイミングでメモリ上から解放するような処理はできませんか? もしくはメモリ上に居座ることのない処理の仕方などありましたら、 考え方を教えていただけるとうれしいです。よろしくお願いします。

  • 関数内、ファイルのstatic変数

    関数内で、static変数を宣言した場合に、その値は保持されると 思いますが、その関数の外からポインタで見る場合にその値は 保証されるのでしょうか? (必ず同じメモリ上に配置されるのでしょうか?) また、関数とファイル内static変数においてスコープ以外に 取り扱いが変わったりするのでしょうか? (配置されるメモリ空間等) よろしくお願い致します。

  • 戻り値で返したオブジェクトの寿命について

    Ruby初心者です。 【前置き】 メソッドで宣言した変数(以下arr)に値(以下[1,2,3])を代入し戻り値として返した場合、 メソッドの戻り値(以下retArr)には、[1,2,3]への参照(arr.object_id)が設定されると認識しております。 ----------------------- def method arr = [1,2,3] return arr end retArr = method() ----------------------- 【質問】 C言語の場合、関数内で宣言したローカル変数のアドレスを戻り値として返却した場合、 関数を抜けた時点で、そのアドレスの内容は保障されなくなりますが、 1.Rubyではその様な問題がなく動作するのは、何故でしょうか? 2.また、メソッド内で宣言したオブジェクト(上記[1,2,3])の寿命はいつまでなのでしょうか? 【備考】 いろいろと調べてみたのですが、オブジェクトの参照(object_id)は、ポインタに近い概念であることは記載されているのですが、その仕組みを理解できずに悩んでします。

    • ベストアンサー
    • Ruby
  • 関数への変数の受け渡しについて

    関数に変数を受け渡すとき、配列とそれ以外の変数では受け渡すものが違いますよね。 変数の場合は、変数の値を関数側の変数にコピーする。 配列の場合は、配列そのもの(配列のポインタ)を関数に渡す。 なぜ配列の場合は値のコピーではなくて、ポインタを渡す仕様になっているんでしょうか。 ひとつめは、どのような意図でそのような仕様になっているのかという質問です。 もうひとつは、関数に配列の値だけを渡すにはどうすればいいのか、つまり元の配列のほうの値は書き換えないで欲しいというときはどうすればよいのかという質問です。 よろしくおねがいします。

  • 関数内で数値入力したときの戻り値は?

     数値を入力して変数に格納する、という作業を複数回繰り返すような数値入力のための関数をつくったとします。そのような場合、関数の宣言や戻り値はどのようにすればよいのでしょうか?  グローバル変数を用いたときにはうまくいったのですが、ローカル変数にかえようとしたらmain関数の中で値が割り当てられていません、となってしまいました。  教えてください。お願いします。

  • 関数の戻り値による変数の初期化

     関数の戻り値で変数を初期化すると、予期せぬ動作をする可能性があると聞いたのですが、実際にそのようなことがあるのでしょうか? また、予期せぬ動作をする場合、そのような現象が起きる環境と原因は何なのでしょうか?    使用している言語はC++なので、例えば下のような動作です。   int a = f();   ・対象の関数が標準関数かどうかは不明です。   ・変数はローカルを想定しています。  ちなみに私は、C,C++を2,3年勉強しており、会社での実践経歴が1年程度です。

  • C言語のメモリ領域確保

    ポインタ変数ををmain関数で宣言し、関数test()にて必要分だけ領域確保してそのアドレスをmain関数のポインタ変数に渡して利用することは可能でしょうか。 (サイズのわからないテキストデータを、十分に大きな配列に入れるのではなく、関数でメモリを動的確保して無駄の無い配列に入れたい等) C言語ではやはり無理で、構造体のリストにするのが一番でしょうか。 初歩的なことで申し訳ありませんがどなたかお願いいたします。

  • プロトタイプ宣言について

    C言語で関数を作成しプロトタイプ宣言するときの質問です。 関数実体の引数に構造体のポインタを宣言します。 プロトタイプ宣言には,構造体のポインタを宣言したのと同じ位置にvoid *を宣言します。 関数実体とプロトタイプ宣言は,異なるファイルです。 このように作成した関数は,VC++2008では,コンパイルできるのですが, なぜ関数実体の宣言とプロトタイプ宣言の型が異なるのにコンパイルできるのでしょうか? また,この関数を別ファイルの関数から呼び出した場合,正しく引数を理解し,正しく処理されます。 これは,言語仕様として正しい書き方なのでしょうか? それとも環境依存の書き方なのでしょうか? ご存知の方がいましたらお答えお待ちしています。

  • スプレッドシートのGASの関数で複数戻り値取得

    googleのスプレッドシートを使っています。 Google Apps Scriptでデータの取得を行っているのですが、 1つの関数から複数の戻り値を得るような方法はありますでしょうか? マイコンのC言語などをやった際に、ポインタ変数を関数の引数に設定して、その関数の引数に配列変数などをアドレス指定で設定することで複数の戻り値を得るような方法があったと思うのですが、GASでも同様の方法などはありますでしょうか? どうぞ、ご教示の程よろしくお願い致します。

このQ&Aのポイント
  • タイムレコーダーの設定方法について解説します。各社員の勤務時間が異なる場合、フルタイム労働者と短時間労働者の休憩時間を個別に設定することができます。
  • たとえば、Aさんは8時間勤務で1時間の休憩を取る場合、Bさんは4時間勤務で30分の休憩を取る場合など、労働者ごとに異なる休憩時間を設定することが可能です。
  • ただし、労働者ごとに休憩時間を設定するためには、それぞれが打刻する方法が必要となります。タイムレコーダーを使用して労働者が自分の勤務時間と休憩時間を打刻することで、正確なデータを管理することができます。
回答を見る

専門家に質問してみよう