
かなり基礎的な質問になるのですが、疑問に思うことがあり、質問をさせていただきます。
関数内で宣言した変数を戻り値として使う場合ですが、ポインタなどではなく実体の場合でも、静的変数として宣言をしたほうが良いのでしょうか?
現実的に考えると、プログラムが関数から出て、呼び出した側の関数が戻り値を受け取るまでの瞬間に、その領域が書き換えられる可能性は極めて低いと思うのですけど、C言語の仕様としてはどうなのでしょうか?
関数内で宣言した戻り値に使う変数には、必ずstaticをつけた方が良いのでしょうか?
もしおわかりでしたら教えて下さい。
No.7ベストアンサー
- 回答日時:
> ちょっと難しく考えすぎちゃっていました。
いえ、とてもよい感覚をお持ちだと思います。
恐らく、「呼び出し元が戻り値を受ける前に、返したいローカル変数が消滅してしまうのではないか」という懸念をお持ちなのではないでしょうか。
だとすれば、お察しの通りです。
おそらく、多くのC言語およびC++言語のコンパイラは、そのようなコードを生成するでしょう。
けれど、安心してください。
そのようなコンパイラであったとしても、戻り値は暗黙的に一時変数に待避されていますので、呼び出し元は戻り値を安全に受けることができます。
つまり、static にする必要はありません。
ただ、一時変数にコピーされるということは、無駄なコピーが1回働くということを意味します。
ですので、大きな構造体などを戻り値に指定するのは避けたほうがよいでしょう。
大きな構造体を返したい場合は、構造体のポインタを引数で受け取るように心がけてください。
目安として、アドレスより大きな構造体は返さないことです。
そうなんです。
>呼び出し元が戻り値を受ける前に、返したいローカル変数が消滅してしまうのではないか
と、考えてしまっていたんです。
もしくは消滅はしないまでも、他の変数などに使われてしまう可能性が絶対にないとはいえないのではないかと・・・
でも、一時変数にコピーされるのなら大丈夫なんですね。
しかも、戻り値に構造体を使わないほうが良い理由というのが初めてきちんとわかりました(^_^;)
ご返答、ありがとうございます。

No.8
- 回答日時:
> 現実的に考えると、プログラムが関数から出て、呼び出した側の関数が戻り値を受け取るまでの瞬間に、その領域が書き換えられる可能性は極めて低いと思うのですけど、C言語の仕様としてはどうなのでしょうか?
この問題はマルチスレッドにしない限り起りません。
(厳密には他にもあると思いますが)
> 関数内で宣言した戻り値に使う変数には、必ずstaticをつけた方が良いのでしょうか?
基本的にする必要はないと思いますが、
ケースバイケースだと思います。
個人的に必要がある思うケースは、
ある関数とあるデータの関係を密接にしたい場合は必要だと思います。
staticの変数を返す関数ではないですが
string.h にある、strtokとstrtok_rの違いについて考えてみてください。
strtokは確実に、staticな変数を使っています。
(もしかするとスレッドローカル変数かもしれませんが)
マルチスレッドを考慮に入れていたわけではないので、基本的には心配する必要がないということですね。
いろいろと勉強になりました。
ご返答ありがとうございます。
No.6
- 回答日時:
>関数内で宣言した変数を戻り値として使う場合ですが、ポインタなどではなく実体の場合でも、静的変数として宣言をしたほうが良いのでしょうか?
変数であろうと、ポインタ変数であろうと、
関数内で宣言された自動変数は関数終了時に破棄されます。
関数内で宣言した変数のポインタを返却しそれ以外の関数でも使用する
なら静的変数にする以外にありませんが、戻り値として
C言語では式を持つreturn文を実行すると、その式の"値"を
関数呼び出し式の値として呼び出し側へ返すという決まりがあります。(C99)
つまり
・値を返すならば自動変数で問題ない。
静的変数を返却する場合むしろマルチスレッド環境などでは、
バグになる可能性もある。
・関数内で宣言した自動変数に値を入れ、その変数のポインタを
上位に返し使用する事はできない。
・関数内で宣言した静的変数ならばそのポインタを返却し上位でも
使用することができるが、やはりマルチスレッド環境などでの
考慮は必要。
って感じの事が分かっていれば大丈夫かと。
値を返す場合は、自動変数で問題なかったんですね。
自分でもずっとそのつもりでいて、実際にそのようなソースを書いてきたのですが、自動変数についていろいろ勉強していたら、ふと疑問に感じてしまって(^_^;)
ご返答、ありがとうございました。
No.5
- 回答日時:
マルチスレッド/マルチタスク環境での心配をしておられるのなら,
むしろ戻り値を static 変数に入れる方が問題です.
関数内で変更する変数を static にしてしまうと,
その関数はリエントラントでなくなりますし,
static 変数の排他制御をしないのならスレッドセーフでもなくなります.
リエントラント (Wikipedia)
http://ja.wikipedia.org/wiki/%E3%83%AA%E3%82%A8% …
スレッドセーフ (Wikipedia)
http://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%AC% …
マルチスレッドのことまでを考慮しているわけではなかったんです。というより、そこまで考慮できるほどの熟練者でもないので(^_^;)
新しい用語もたくさん教えていただいたので、これから勉強してみます。
ご返答、ありがとうございました。
No.2
- 回答日時:
>呼び出した側の関数が戻り値を受け取るまでの瞬間に、
>その領域が書き換えられる可能性
マルチスレッドのプログラムですか?
排他制御と static 変数には何の関係もないと思いますが。
変数を static と宣言することによって tadasuke200 さんが期待している効果を補足すると、アドバイスを得やすいでしょう。
マルチスレッドまで考えてのことではないのですが、例えば、free関数などで開放した領域をすぐに使用するとか、基本的には動くけどCの仕様としては間違っているというような状況なのかと考えたりしてしまいまして・・・
難しく考えすぎました(^_^;)
ご返答ありがとうございます。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
ポインタについて
-
型のバイト数はビルド時に全部...
-
Visual C++2010 Express
-
CWnd::EnableWindow()の扱い方
-
プーさんのマウスポインタを教...
-
Wポインタを教えて下さい!
-
ポインタへの値の代入時の警告...
-
連結リスト 要素の入れ替え
-
init関数の意味
-
#define NULL ((void *)0) の弊害
-
画像の処理について
-
structをポインタ宣言時の領域
-
パスからファイル名を抽出
-
printfとscanfの違いって・・・
-
_TCHAR、LPCWSTRについて
-
ポインタの意味がよくわからず...
-
C言語のプログラムをJavaに...
-
Wordでのリンク方法(Ctrlキー...
-
【C言語】戻り値が構造体の関数
-
どうしてエラーになるかわかり...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C言語のポインタに直接アドレス...
-
fopne で失敗する原因
-
戻り値で構造体を返すことは可...
-
LPSTR型の初期化について
-
Run-Time Check Failure #3とい...
-
ExcelVBAでのkernel32(64bit)
-
参照型で受け取った引数をポイ...
-
init関数の意味
-
セグメントエラー
-
アプリを32bitから64bit移行
-
ハンドルはポインタか
-
ハンドル、アドレス、ポインタ...
-
C言語でのconstを返す関数
-
C++で関数ポインタから関数名を...
-
パスからファイル名を抽出
-
ReadFileの読み込みエラーについて
-
#define NULL ((void *)0) の弊害
-
CImage GetBitsメソッドについて
-
ポインタ変数の疑問
-
Cで作成したDLL関数をVBから呼...
おすすめ情報