
スタックフレームの消滅についての質問です。
以下のCのプログラムですが、
char *sayHello(void) {
char s[] = "hello";
return s;
}
int main(void) {
char *s;
s = sayHello();
printf("%s\n", s);
return 0;
}
コンパイルすると、
warning: address of stack memory associated with local variable
's' returned [-Wreturn-stack-address]
のワーニングが出て、実行すると、nullが返ってくる様ですが、
書籍にも、「ローカル変数は、スタックフレームの消滅と共に消えて無くなる」とあるのですが、
実際にアセンブルしたコードを見てみると、リターン後は、sayHello関数のスタックフレームは
無くなり、ebpのベースポインタとespのスタックポインタがそれぞれmain関数のBOTTOMとTOPを指す様になるのですが、sayHelloの関数領域は、次の何かの関数が呼び出されて上書きされない限り、残っている様に思うのですが、アセンブラの処理としてどこかの記述で使い終わったスタックフレームの領域を消去する様な記述がされている様な所とかあるのでしょうか?
No.6ベストアンサー
- 回答日時:
補足確認、および、共有ありがとうございます
コンパイラが意図的に戻り値を変更しているようですね。
gccが変更しているのは、ググったらありました
https://yohhoy.hatenadiary.jp/entry/20160509/p1
No.5
- 回答日時:
コードは典型的な懸垂参照なので、言語仕様上は何が起こるか分かりませんね。
printfでnull表示されるからnullが返っていると判断されているようですが、printf自体が関数なのでprintfが呼び出された時点でスタックフレームは上書きされているわけで、printf関数内で何らかの異常対処をしている可能性もあります。
No.4
- 回答日時:
No3です
>返される値は使っている環境によると思います。
環境によって、nullが戻り値として返ってくる可能性があると思ってるのであれば、それは違います
質問者さんのコードで、nullが返ってくるケースは、何かのバグか、コンパイラが意図的変更をしない限りnullは返ってきません
納得する、しないは、質問者さんが決められることですが、printfで、sayHello()関数内部で、sのアドレス表示と、main()でsの戻り値を表示すれば、何が起きてるのか、もう少し確認できると思います
No.3
- 回答日時:
ローカル変数は、通常その関数が呼ばれたときに、スタック上に確保するので、関数が戻るとそれ以降ローカル変数領域のメモリの保証はないので、コンパイラが、そのコードを解析したときに、nullポインターを返すようなコードを生成してるのでしょう。
スタックフレームを0フィルしてるわけではないと思います少なくとも、コンパイラはコンパイル時に、そのワーニングが出せるということは、sayHello()関数が破棄予定のローカル変数のアドレスを返していると認識していることを裏付けているので
プログラムが、たまたま、動作してしまうと、いくらテストをしても問題が起きない可能性があるので、nullポインターを返すコードを生成することで、スタックエリアにアクセスしようとしたときに、必ずexceptionが発生するようにコンパイラが意図しているのでしょう
質問者さんが、他の関数を呼び出されない限り、残っているのでは?という推測は、コンパイラの仕様にもよりますが、ほぼ、間違いなくあってます
逆の言い方をすると、そのワーニングを消すようなオプションをつけてコンパイルすれば、多分、スタック上のポインターが戻され、問題なく動作しますが、それは、たまたま動作してるに過ぎないです
No.1
- 回答日時:
言語仕様ではいかなる保証もない. つまり「残ったまま」かもしれないし「何も言わないまま消滅してしまう」かもしれない. 少なくとも, 「残っている」ことを前提にするプログラムは「行儀が悪い」といえる.
ところで「実行すると、nullが返ってくる様ですが」というのはどうやって確かめた?
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- C言語・C++・C# const char** p;のとき、free(p)でC4090エラーとなるのはなぜですか 3 2023/03/31 16:28
- C言語・C++・C# c言語でユーザ関数を利用して入力された文字列を反転させるプログラムを作りたいです。 3 2023/01/29 19:47
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# sprintf()の使い方について 1 2022/08/17 16:16
- C言語・C++・C# C言語プログラム変更 2 2022/12/21 15:03
- 大学・短大 C言語線形リストの問題です 3 2022/12/22 00:45
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# C pointer? or... 2 2022/03/29 00:47
- C言語・C++・C# Cのdoubleの浮動小数点表示について 3 2023/04/17 13:14
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
GCCで関数の引数が渡らない
-
逆ポーランド記法
-
pthreadのスタックサイズ設定取...
-
ヘッドセットとスカイプとBluet...
-
スタックの仕組み
-
スタックとキューの使い所
-
VC6でコンパイルでスタックの領...
-
VB.netでDLLを読み込んで実行す...
-
二分木について
-
スタックフレームの消滅
-
プログラムの規模を表す単位「k...
-
ubuntuで デイスク/deb/loopと...
-
ライン数とステップ数の違いに...
-
現在、タイピング速度をあげた...
-
【QNAP NAS】LANポートについて...
-
512MB・1Gとは・・・
-
ブラインドタッチをマスターし...
-
英語のタイピング
-
サブネットマスク
-
STEPについて
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
最大スタックサイズを大きくす...
-
gccでスタックサイズを変更する...
-
VB.netでDLLを読み込んで実行す...
-
printf / sprintf のスタック消...
-
スタックフレームの消滅
-
H8マイコン スタック領域に...
-
ハイパーカード
-
関数のプロローグとエピローグ...
-
スタック領域変更
-
再帰処理を非再帰処理に書き換...
-
WINAPについて
-
無償Borland5.51でスタックメモ...
-
_CRTIMPの意味は?
-
エラーメッセージが・・・
-
プログラミングについての質問...
-
OCXからのコールバックを繰り返...
-
スタックとキューの使い所
-
マス目上の移動のアルゴリズム
-
WINDOWSなどのOSを構成している...
-
エラー?メッセージ
おすすめ情報
実行ファイルを実行しただけです。
返される値は使っている環境によると思います。
sayHello()関数内のsとmain()関数内のsを表示させてみたのですが、
clangのコンパイラを使った場合、
0x7ffee5b8f9ca
0x7ffee5b8f9ca
n?̃?
gccのコンパイラを使った場合、
0x7ffee330891a
0x0
(null)
になります。
gccの場合、main()ではヌルポインタ(0x0)が戻ってきているみたいです。