gcc编译器优化给咱们带来的麻烦???

今天看到一个颇有趣的程序,以下:优化

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赋值时编译器用的是数值,并无引用地址。

因此,我的猜想,编译器在这方面有一个优化功能:若是一个变量在定义时赋值常量,那么在引用它的时候,编译器会直接用该常量数值代替地址的引用来节省时间,可是也给咱们带来了之外的麻烦。

这些都是我的的观点,但愿各位指教!!!

相关文章
相关标签/搜索