スタックアロケーターの解説を始める前に一つクリアにしときましょう。
まずスタックは上位アドレスから下位アドレスに下方向に拡大していきます。
main.cpp.
1 #include <cstdio> 2 3 void bar(){ 4 int a,b,c,d,e; 5 std::printf("a: %p\n",&a); 6 std::printf("b: %p\n",&b); 7 std::printf("c: %p\n",&c); 8 std::printf("d: %p\n",&d); 9 std::printf("e: %p\n",&e); 10 } 11 12 void foo(){ 13 int a,b,c,d,e; 14 std::printf("a: %p\n",&a); 15 std::printf("b: %p\n",&b); 16 std::printf("c: %p\n",&c); 17 std::printf("d: %p\n",&d); 18 std::printf("e: %p\n",&e); 19 std::printf("=== bar ===\n"); 20 bar(); 21 } 22 23 int main(){ 24 int a,b,c,d,e; 25 std::printf("a: %p\n",&a); 26 std::printf("b: %p\n",&b); 27 std::printf("c: %p\n",&c); 28 std::printf("d: %p\n",&d); 29 std::printf("e: %p\n",&e); 30 std::printf("=== foo ===\n"); 31 foo(); 32 return 0; 33 }
ビルドと実行結果.
$ g++ main.cpp $ ./a.out a: 0x7fffd7fa7464 b: 0x7fffd7fa7468 c: 0x7fffd7fa746c d: 0x7fffd7fa7470 e: 0x7fffd7fa7474 === foo === a: 0x7fffd7fa7434 b: 0x7fffd7fa7438 c: 0x7fffd7fa743c d: 0x7fffd7fa7440 e: 0x7fffd7fa7444 === bar === a: 0x7fffd7fa7404 b: 0x7fffd7fa7408 c: 0x7fffd7fa740c d: 0x7fffd7fa7410 e: 0x7fffd7fa7414
このコードを見ると関数内で宣言順で変数のアドレスをチェックすると 4 バイト間隔となっています。
しかし関数をコールすると、アドレスは下方向にシフトします。
例えば main 関数の a は 0x7fffd7fa7464 ですが foo 関数の a は 0x7fffd7fa7434 というように値が減少しています。
まあこんな感じで変数の宣言順というのはわかったのですが、アロケーターにとっては配列型のアドレス構造の方を知りたいです。
では配列内のアドレスはどうなのか確かめて見ましょう。
main.cpp.
1 #include <cstdio> 2 3 int main() 4 { 5 int x[10]; 6 7 for(int i = 0; i < 10; ++i) 8 { 9 std::printf("%p\n",x+i); 10 } 11 12 return 0; 13 }
ビルドと実行結果.
$ g++ main.cpp $ ./a.out 0x7ffca911c040 0x7ffca911c044 0x7ffca911c048 0x7ffca911c04c 0x7ffca911c050 0x7ffca911c054 0x7ffca911c058 0x7ffca911c05c 0x7ffca911c060 0x7ffca911c064
これは文句なく上方向に動いていますね。
0x7ffca911c040 から 0x7ffca911c064 だと一目瞭然です。
つまりスタックにおいては、一旦宣言・定義した配列・変数のアドレスは減算でなく加算されるってことです。
Copyright 2018-2019, by Masaki Komatsu