c++におけるconst定数の記憶位置検討
2821 ワード
まず奇妙なコードを見てみましょう.
以上の分析から以上の結論を得ることができる:1.const定数に対してアドレスを取ると、コンパイラはメモリ割り当てを行い、定数テーブルに記録されたアドレスではなく即時数に変換してメモリに格納します.
2.定数を使用する場合、コンパイラは定数テーブルに戻って対応する定数をクエリーし、メモリ割り当てに関係なく、作成した定数のメモリアドレスにも関係なく置き換えます.
#include
int main()
{
const float intValue=2.2;
float *j=(float *)&intValue;
*j=1.1;
printf("intValue address:0x%x
",&intValue);
printf("j address:0x%x
",j);
printf("j:%f
",*j);
printf("intValue:%f
",intValue);
return 0;
}
の出力結果は次のとおりです.intValue address:bfd8dddc
j address:bfd8dddc
j:1.100000
intValue:2.200000
これは、なぜアドレスが同じなのか、指す値が異なるのか~~コンパイラがconst定数を処理するいくつかのメカニズムを検討します.以上のコード生成のアセンブリは以下の通りです..file "constASM.cpp"
.section .rodata //rodata , printf
.LC2:
.string "intValue address:0x%x
"
.LC3:
.string "j address:0x%x
"
.LC4:
.string "j:%f
"
.LC6:
.string "intValue:%f
"
.text
.globl main
.type main, @function
main:
.LFB2:
leal 4(%esp), %ecx //esp:Stack Pointer, ,
.LCFI0:
andl $-16, %esp
pushl -4(%ecx)
.LCFI1:
pushl %ebp //ebp
.LCFI2:
movl %esp, %ebp
.LCFI3:
pushl %ecx
.LCFI4:
subl $36, %esp //esp 36, 36
.LCFI5:
movl $0x400ccccd, %eax //&intValue , , .LC5,
movl %eax, -12(%ebp) // (ebp-12) 0x400ccccd,0x400ccccd, 2.2
leal -12(%ebp), %eax
movl %eax, -8(%ebp) // (ebp-8) 0x400ccccd
movl -8(%ebp), %edx // (ebp-8) edx
movl $0x3f8ccccd, %eax
movl %eax, (%edx) // (ebp-8) 0x3f8ccccd, 1.1
leal -12(%ebp), %eax
movl %eax, 4(%esp) // (ebp-12) (4+esp) printf
movl $.LC2, (%esp) // .LC2 (esp) , printf
call printf //printf("intValue address:0x%x
",&intValue);
movl -8(%ebp), %eax
movl %eax, 4(%esp)
movl $.LC3, (%esp)
call printf //printf("j address:0x%x
",j);
movl -8(%ebp), %eax
flds (%eax) // , (ebp-8)
fstpl 4(%esp)
movl $.LC4, (%esp)
call printf //printf("j:%f
",*j);
fldl .LC5 // , LC5, !!! intValue, !!
fstpl 4(%esp) //
movl $.LC6, (%esp)
call printf //printf("intValue:%f
",intValue);
movl $0, %eax
addl $36, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.LFE2:
.size main, .-main
.section .rodata
.align 8
.LC5:
.long -1610612736
.long 1073846681
.section .eh_frame,"a",@progbits
.Lframe1:
.long .LECIE1-.LSCIE1
.LSCIE1:
.long 0x0
.byte 0x1
.
.//
.
.LEFDE1:
.ident "GCC: (GNU) 4.3.0 20080428 (Red Hat 4.3.0-8)"
.section .note.GNU-stack,"",@progbits
以上の分析から以上の結論を得ることができる:1.const定数に対してアドレスを取ると、コンパイラはメモリ割り当てを行い、定数テーブルに記録されたアドレスではなく即時数に変換してメモリに格納します.
2.定数を使用する場合、コンパイラは定数テーブルに戻って対応する定数をクエリーし、メモリ割り当てに関係なく、作成した定数のメモリアドレスにも関係なく置き換えます.