c++中const常量的儲存位置探討
阿新 • • 發佈:2019-01-26
首先看一段詭異的程式碼:
#include <stdio.h>
int main()
{
const float intValue=2.2;
float *j=(float *)&intValue;
*j=1.1;
printf("intValue address:0x%x\n",&intValue);
printf("j address:0x%x\n",j);
printf("j:%f\n",*j);
printf("intValue:%f\n",intValue);
return 0;
}
輸出結果如下:這就納悶了,為什麼地址一樣,而所指的值不一樣呢~~這就要探討一下編譯器在處理const常量方面的一些機制了,以上程式碼生成的彙編如下:intValue address:bfd8dddc j address:bfd8dddc j:1.100000 intValue:2.200000
.file "constASM.cpp" .section .rodata //rodata區,此處儲存printf中的一些常量 .LC2: .string "intValue address:0x%x\n" .LC3: .string "j address:0x%x\n" .LC4: .string "j:%f\n" .LC6: .string "intValue:%f\n" .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\n",&intValue); movl -8(%ebp), %eax movl %eax, 4(%esp) movl $.LC3, (%esp) call printf //printf("j address:0x%x\n",j); movl -8(%ebp), %eax flds (%eax) //浮點數壓棧,壓入的是(ebp-8)地址的值 fstpl 4(%esp) movl $.LC4, (%esp) call printf //printf("j:%f\n",*j); fldl .LC5 //浮點數壓棧,壓入的是LC5,這裡就是區別!!!直接從符號表中找到intValue,跟前面的記憶體操作無關!! fstpl 4(%esp) // movl $.LC6, (%esp) call printf //printf("intValue:%f\n",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常量取地址時,編譯器會進行記憶體分配,並將常量轉換為立即數存入記憶體,而不是存入記錄在常量表中的地址