KDOC 228: 変数を書いた順番とアドレスの関係はコンパイラによって異なる
この文書のステータス
- 作成
- 2024-08-25 貴島
- レビュー
- 2024-09-09 貴島
概要
コンパイラによって、コードで変数を初期化した順番とアドレスの順番は異なることがある。
最初に、gcc。
int main() {
char base = 0;
char a = 'a';
char b = 'b';
char c = 'c';
printf("%p: base\n", &base);
printf("%p: a\n", &a);
printf("%p: b\n", &b);
printf("%p: c\n", &c);
}
0x7fffa55f0a84: base
0x7fffa55f0a85: a
0x7fffa55f0a86: b
0x7fffa55f0a87: c
つまり、メモリは↓このようになっているように見える。コードで変数を初期化した順番とアドレスの順番が一致している。スタックだからアドレスが書いた逆順になる、というわけではない。
^番地小(低)
| ...84: base |
| ...85: a |
| ...86: b |
| ...87: c |
v番地大(高)
アセンブラを見てみると、(低)base, a, b, c(高)順のアドレスになっているのを確認できた。
.file "main.c"
.text
.section .rodata
.LC0:
.string "%p: base\n"
.LC1:
.string "%p: a\n"
.LC2:
.string "%p: b\n"
.LC3:
.string "%p: c\n"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
endbr64
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movq %fs:40, %rax
movq %rax, -8(%rbp)
xorl %eax, %eax
movb $0, -12(%rbp) ; 👈
movb $97, -11(%rbp) ; 👈
movb $98, -10(%rbp) ; 👈
movb $99, -9(%rbp) ; 👈
leaq -12(%rbp), %rax
movq %rax, %rsi
leaq .LC0(%rip), %rax
movq %rax, %rdi
movl $0, %eax
call printf@PLT
leaq -11(%rbp), %rax
movq %rax, %rsi
leaq .LC1(%rip), %rax
movq %rax, %rdi
movl $0, %eax
call printf@PLT
leaq -10(%rbp), %rax
movq %rax, %rsi
leaq .LC2(%rip), %rax
movq %rax, %rdi
movl $0, %eax
call printf@PLT
leaq -9(%rbp), %rax
movq %rax, %rsi
leaq .LC3(%rip), %rax
movq %rax, %rdi
movl $0, %eax
call printf@PLT
movl $0, %eax
movq -8(%rbp), %rdx
subq %fs:40, %rdx
je .L3
call __stack_chk_fail@PLT
.L3:
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0"
.section .note.GNU-stack,"",@progbits
.section .note.gnu.property,"a"
.align 8
.long 1f - 0f
.long 4f - 1f
.long 5
0:
.string "GNU"
1:
.align 8
.long 0xc0000002
.long 3f - 2f
2:
.long 0x3
3:
.align 8
4:
--------------------------------
|-12(%rbp): base |
|-11(%rbp): a |
|-10(%rbp): b |
| -9(%rbp): c |
いっぽうclangでコンパイルした場合、先に書いた変数が高位アドレスとなる。
0x7ffe71de7317: base
0x7ffe71de7316: a
0x7ffe71de7315: b
0x7ffe71de7314: c
--------------------
^番地小(低)
| ...14: c |
| ...15: b |
| ...16: a |
| ...17: base |
v番地大(高)
つまり、コードで変数を初期化した順番と、アドレスの順番は必ずしも逆にはならないことがある。なぜそうなるのかは、いつか調べる。
関連
抽象。
- 書いた順番と実際の配置の対応は、処理する側しだいで保証されない
関連。
- 動機: KDOC 226: 任意のアドレスに読み書きする。調べている途中で発見した
- 補足: KDOC 227: フィールド定義の順番によってメモリサイズが変わることがある。書いた順番と配置の関係のもう1つの側面