今天看到一个颇有趣的程序,以下:优化
int main() { const int a = 1; int *b = (int*)&a; *b = 21; printf("%d, %d", a, *b); return 0; }
当我第一眼看到这个程序的时候,我想固然的认为输出结果是21, 21,可是我错了blog
一时很难理解,因而我又输出了它们的地址:内存
int main() { const int a = 1; int *b = (int*)&a; *b = 21; printf("%d, %d", a, *b); printf("\n%p, %p", &a, &*b); return 0; }
它们的地址是同样的,看到这里我更加的不解,因而我试着查看一下汇编代码。编译器
int main() { const int a = 1; int *b = (int*)&a; *b = 21; printf("%d", a); return 0; }
对应汇编代码以下:编译
这里获得的是at&t的汇编代码,与intel不一样之处在于:class
1,指令格式为:指令名称 元操做数 目的操做数变量
2,寄存器前加%引用
3,操做数前加$程序
4,0x4(%esp)为内存寻址,实际表示的是esp寄存器中的内容 + 4(若是不是很明白,望自行查找资料,本人知识有限)im
咱们首先看标号为1的行,对应c语句为const int a =1,这是把1放进地址为0x18(%esp)的地方,再来看标号2的地方,对应的printf语句,发现并无引用地址为0x18(%esp)的地方的值,而是把1直接放到了0x4(%esp),而后输出。
因此我的认为,之因此会出现最开始的结果,是由于编译器给咱们作了一些优化致使的。为了证实个人观点,我修改了程序:
int main() { int c = 1; const int a = c; int *b = (int*)&a; *b = 21; printf("%d, %d", a, *b); return 0; }
输出结果为:
对应的汇编代码为:
在标号1处,咱们能够肯定a存放在0x14(%esp)的地方,在标号2处,对应的printf语句,此语句从右向左处理参数,2处理的是*b,3处理的是a,这时看到用的是地址,而不是直接用数值,同时看标号0处,咱们是将c赋值1,再给a赋值时编译器用的是数值,并无引用地址。
因此,我的猜想,编译器在这方面有一个优化功能:若是一个变量在定义时赋值常量,那么在引用它的时候,编译器会直接用该常量数值代替地址的引用来节省时间,可是也给咱们带来了之外的麻烦。
这些都是我的的观点,但愿各位指教!!!