首先看一段诡异的代码:
#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;
}
intValue address:bfd8dddcj address:bfd8dddcj:1.100000intValue:2.200000这就纳闷了,为什么地址一样,而所指的值不一样呢~~这就要探讨一下编译器在处理const常量方面的一些机制了,以上代码生成的汇编如下:
.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, @functionmain:.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常量取地址时,编译器会进行内存分配,并将常量转换为立即数存入内存,而不是存入记录在常量表中的地址