• ベストアンサー

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

専門家に質問してみよう