スタックが低いアドレスに向かって積まれない場合はありますか?

投稿者: Anonymous

私はコンピュータについて勉強中で、スタックが低いアドレスに向かって積まれることを学びました。
そして、実験的にこのようなコードを書きました

alignas(long) int k = 0xcafecafe;
k++;
uint8_t buf[] = {0,1,2,3,4,5,6,7};
alignas(16) uint8_t x,y,z;
x = 1;
y = 2;
z = 3;

lldbでメモリを見てみると、確かにx,y,zは上にむかって積まれていましたが、0xcafecafe+1は配列の0x7ffeefbff880: 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07より上に積まれています。
これはなぜですか?

(lldb) x/128xb &z
0x7ffeefbff840: 0x03 0xf8 0xbf 0xef 0xfe 0x7f 0x00 0x00
0x7ffeefbff848: 0xa0 0xf8 0xbf 0xef 0xfe 0x7f 0x00 0x00
0x7ffeefbff850: 0x02 0x00 0x00 0x00 0x01 0x00 0x00 0x00
0x7ffeefbff858: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7ffeefbff860: 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7ffeefbff868: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7ffeefbff870: 0xff 0xca 0xfe 0xca 0x00 0x00 0x00 0x00
0x7ffeefbff878: 0x00 0x00 0xff 0xff 0x00 0x00 0x00 0x00
0x7ffeefbff880: 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07
0x7ffeefbff888: 0xc8 0x00 0x9a 0x1c 0xb6 0x13 0x7a 0x6c
0x7ffeefbff890: 0xa8 0xf8 0xbf 0xef 0xfe 0x7f 0x00 0x00
0x7ffeefbff898: 0xe5 0x82 0xec 0x69 0xff 0x7f 0x00 0x00
0x7ffeefbff8a0: 0xe5 0x82 0xec 0x69 0xff 0x7f 0x00 0x00
0x7ffeefbff8a8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7ffeefbff8b0: 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7ffeefbff8b8: 0x78 0xfa 0xbf 0xef 0xfe 0x7f 0x00 0x00

解決

関数内の自動変数の配置順番なんかは、コンパイラの自由裁量の範囲で、どうにでも変わるものでしょう。

例えばこんな記事があります。
第八回-03 メインメモリとアドレス

いずれにせよ、変数をメモリ上にどう配置するかはコンパイラの仕事なので、任せておけば問題はない。
しかし、変数 (今回学んだのは自動変数と呼ばれるもの) がメモリに配置されるイメージを掴むことは大変重要である。

続きでこれとか。
第九回-01 スタック領域上での配列の配置
第九回-02 関数内の変数のメモリ配置

こちらはスタック内とは書いていないので固定のデータ領域かもしれませんが。
変数がメモリ上でどのように配置されているかメモ

デバッグ版かリリース版か、最適化の有無および最適化もサイズ優先か速度優先か、など様々な条件により変数のレイアウトは変わるでしょう。

「スタックが低いアドレスに向かって積まれることを学びました。」 に関しては、こちらの概念の方が相応しいですね。
C言語 スタックメモリ【ローカル変数が確保される仕組みを解説】

説明の主題とは微妙に違いますが、関数の中から更に関数を呼び出していくと、スタックの低いアドレスに向かって消費量が伸びていきます。

ただし、関数を呼び出すときのパラメータの積み方は、OSのAPIの呼び出しとか、プログラミング言語を混合して使う等のために決まっています。
それでも、いくつかのパターンがあって、どれが使われているか、どれを使うかは、選択する必要があります。

回答者: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *