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

今天看到一个很有趣的程序,如下:

1
2
3
4
5
6
7
8
9
int main()
{
    const int a = 1;
    int *b = (int*)&a;
    *b = 21;
 
    printf("%d, %d", a, *b);
    return 0;
}

当我第一眼看到这个程序的时候,我想当然的认为输出结果是21, 21,但是我错了

一时很难理解,于是我又输出了它们的地址:

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不同之处在于:

1,指令格式为:指令名称 元操作数 目的操作数

2,寄存器前加%

3,操作数前加$

4,0x4(%esp)为内存寻址,实际表示的是esp寄存器中的内容 + 4(如果不是很明白,望自行查找资料,本人知识有限)

我们首先看标号为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赋值时编译器用的是数值,并没有引用地址。

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

这些都是个人的观点,希望各位指教!!!

gcc编译器优化给我们带来的麻烦???的更多相关文章

  1. 【转】C 编译器优化过程中的 Bug

    C 编译器优化过程中的 Bug 一个朋友向我指出一个最近他们发现的 GCC 编译器优化过程(加上 -O3 选项)里的 bug,导致他们的产品出现非常诡异的行为.这使我想起以前见过的一个 GCC bug ...

  2. GCC 编译优化指南(转)

    GCC 编译优化指南(转) http://www.jinbuguo.com/linux/optimize_guide.html 作者:金步国 版权声明 本文作者是一位开源理念的坚定支持者,所以本文虽然 ...

  3. GCC 编译优化指南

    转自: http://www.jinbuguo.com/linux/optimize_guide.html GCC 编译优化指南 作者:金步国[www.jinbuguo.com] 版权声明 本文作者是 ...

  4. GCC编译优化指南【作者:金步国】

    GCC编译优化指南[作者:金步国] GCC编译优化指南 作者:金步国 版权声明 本文作者是一位自由软件爱好者,所以本文虽然不是软件,但是本着 GPL 的精神发布.任何人都可以自由使用.转载.复制和再分 ...

  5. GCC 编译优化指南【转】

    转自:http://www.jinbuguo.com/linux/optimize_guide.html 版权声明 本文作者是一位开源理念的坚定支持者,所以本文虽然不是软件,但是遵照开源的精神发布. ...

  6. gcc编译器命令使用详解

    1.gcc包含的c/c++编译器gcc,cc,c++,g++,gcc和cc是一样的,c++和g++是一样的,(没有看太明白前面这半句是什么意思:))一般c程序就用gcc编译,c++程序就用g++编译 ...

  7. 在CentOS 7.2下升级gcc编译器的版本

    默认情况下,CentOS 7.2预装的gcc版本是4.8.x,通过执行命令 gcc -v 可以看到,一般情况下这个版本的编译器已经满足需要了,但是某些特殊的时候为了支持C++更高的特性,需要对gcc编 ...

  8. GCC编译器编译链接

    在gcc编译器环境下,常见的文件扩展名的含义如下: .c:C源程序,经过预编译后的源程序也为.c文件,它可以通过-E参数输出. .h:头文件 .s:经过编译得到的汇编程序代码,它可以通过-S参数输出. ...

  9. Linux安装gcc编译器详解

    本人使用的是CentOS 6.5 64位系统,由于在安装系统的时候并没有勾选安装gcc编译器,因此需要自行安装gcc编译器. 使用yum安装gcc 对于配备了yum的Linux发行版而言,安装gcc编 ...

随机推荐

  1. cocos2d-x多分辨率和随后的自适应CCListView的bug修复

    cocos2d-x多分辨率自适配及因此导致的CCListView的bug修复 cocos2d-x是一款众所周知的跨平台的游戏开发引擎.因为其跨平台的特性.多分辨率支持也自然就有其需求. 因此.在某一次 ...

  2. java设计模式之十桥接模式(Bridge)

    桥接模式就是把事物和其具体实现分开,使他们可以各自独立的变化.桥接的用意是:将抽象化与实现化解耦,使得二者可以独立变化,像我们常用的JDBC桥DriverManager一样,JDBC进行连接数据库的时 ...

  3. Codeforces 474A Keyboard (水

    题目链接:点击打开链接 键盘移位了,问输出相应的字母 #include <cstdio> #include <cstring> char a[105]; char b[3][1 ...

  4. PhotoShop CC安装抠图插件KnockOut 2

    1.KnockOut 2只有32位版本,因此需要给32位的PhotoShop CC安装. 2.下载地址:http://www.cr173.com/soft/28207.html 3.安装KnockOu ...

  5. 摘录DirectShow数据,视频采集

    DirectShow在,数据流(Data Flow)它们是依次流过每Filter的.管理其数据具有其自己的方法,并且并没有向用户提供一个统一的接口,供用户操作数据流.这里以提取视频採集在的每帧为位图数 ...

  6. [ACM] POJ 2506 Tiling (递归,睑板)

    Tiling Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7487   Accepted: 3661 Descriptio ...

  7. 过度补脑系列:Nokia的不归路

    没有数据,没有调查,只是突然想起诺基亚... 23号的一节酱油课,脑海中突然闪过两个关键字--nokia & android 于是用手机百度了一下,竟然真的出了新机型,NokiaX,X东24日 ...

  8. iOS文档序列化(对象归档)

    对象归档: 概念: 对象归档是指将对象写入文件保存在硬盘,当再次又一次打开程序时,能够还原这些对象.也称:对象序列化.对象持久化. 数据持久性的方式(事实上就是3类) 1,NSKeyedArchive ...

  9. leetcode 34 Search Insert Position

    Given a sorted array and a target value, return the index if the target is found. If not, return the ...

  10. SQL Server中生成测试数据

    原文:SQL Server中生成测试数据 简介      在实际的开发过程中.很多情况下我们都需要在数据库中插入大量测试数据来对程序的功能进行测试.而生成的测试数据往往需要符合特定规则.虽然可以自己写 ...