昨天碰到一个很奇怪的问题,首先来看这段代码:

 #include<stdio.h>
int main(int argc,char *argv[])
{
long num1 = ;
long long num2 = ; long long res1 = num1 * num1;
long long res2 = num2 * num2; printf("res1 = %lld\n",res1);
printf("res2 = %lld\n",res2); return ;
}

  程序的运行结果如下:

  

  这里感觉很奇怪,203879并没有超过4个字节的范围,但是它的平方超过了,于是我把它的结果存放在一个8字节数中,为什么最终结果还是显示溢出了呢?

  然后我又写了一段程序,把它的汇编代码拿出来分析了一下?程序如下:

 int main(int argc,char *argv[])
{
long muln = ;
long long mulnl = ; long long num1 = * ;
long long num2 = muln * muln;
long long num3 = mulnl * mulnl; return ;
}

  这里我分成三种情况,一种是直接的一个整数当乘数,一个是long型的整数当乘数,还有一个是long long型的整数当作乘数,然后分别计算他们的平方,我用gdb调试的结果如下:

  

  其中前两种情况都溢出了,只有第三种情况正常。然后我们再来查看一下他们的汇编代码,这是我用objdump反汇编出来的汇编代码:

  

 int main(int argc,char *argv[])
{
: push %ebp
: e5 mov %esp,%ebp
: e4 f8 and $0xfffffff8,%esp
804839a: ec sub $0x30,%esp
long muln = ;
804839d: c7 0c 1c movl $0x31c67,0xc(%esp)
80483a4:
long long mulnl = ;
80483a5: c7 1c movl $0x31c67,0x10(%esp)
80483ac:
80483ad: c7 movl $0x0,0x14(%esp)
80483b4: long long num1 = * ;
80483b5: c7 b1 movl $0xad90b171,0x18(%esp)
80483bc: ad
80483bd: c7 1c ff ff ff movl $0xffffffff,0x1c(%esp)
80483c4: ff
long long num2 = muln * muln;
80483c5: 8b 0c mov 0xc(%esp),%eax
80483c9: 0f af 0c imul 0xc(%esp),%eax
80483ce: c2 mov %eax,%edx
80483d0: c1 fa 1f sar $0x1f,%edx
80483d3: mov %eax,0x20(%esp)
80483d7: mov %edx,0x24(%esp)
long long num3 = mulnl * mulnl;
80483db: 8b mov 0x14(%esp),%eax
80483df: c1 mov %eax,%ecx
80483e1: 0f af 4c imul 0x10(%esp),%ecx
80483e6: 8b mov 0x14(%esp),%eax
80483ea: 0f af imul 0x10(%esp),%eax
80483ef: c1 add %eax,%ecx
80483f1: 8b mov 0x10(%esp),%eax
80483f5: f7 mull 0x10(%esp)
80483f9: d1 add %edx,%ecx
80483fb: ca mov %ecx,%edx
80483fd: mov %eax,0x28(%esp)
: 2c mov %edx,0x2c(%esp)
: mov %eax,0x28(%esp)
: 2c mov %edx,0x2c(%esp) return ;
804840d: b8 mov $0x0,%eax
}

  首先来看num1的代码(16~20行),203879(31C67H)平方为41566646641(9AD90B171H),编译器直接把这个结果计算了出来,然后取出结果的4个字节,存放到了num1中,然后再用符号位来填充高4字节。

  接下来我们再来看num2的代码(21~27行),首先它把203879存放到eax里面,再把相乘的平方结果存放到eax里面,由于eax是32位,所以存放的时候就舍去了高4位,只存放了低4个字节。接下来做的就是判断这个数的符号位是什么,然后再用移位运算得到32个1存放在edx里面,最后再把这个edx的值存放到num2的高四个字节里面。

  OK,通过上面这段汇编代码分析,我们再来从C语言的概念上来分析这句代码:

  long long num2 = muln * muln ;

  首先muln是一个4字节的整数,然后muln * muln得到的结果也是一个四字节的整数(这里产生了溢出),然后再把这个结果转换成8字节的整数,存放到num2中。所以我们最终得到的结果也是一个溢出的结果。

  分析完了之后,发现我这是舍进求远啊,现在也不知怎么了,遇到点啥就喜欢反汇编出来看看。。。

从一个乘法来分析C语言的更多相关文章

  1. C++写一个简单的解析器(分析C语言)

    该方案实现了一个分析C语言的词法分析+解析. 注意: 1.简单语法,部分秕.它可以在本文法的基础上进行扩展,此过程使用自上而下LL(1)语法. 2.自己主动能达到求First 集和 Follow 集. ...

  2. Go将统治下一个10年?Go语言发展现状分析

    “本文是国内Go语言大中华区首席布道师——许式伟,在QCon2015上海站上的分享.他预测Go语言10年内一定会超过C和java,并且统治这一个10年. Go语言语法及标准库变化 Go从1.0版本到现 ...

  3. 《C专家编程》第三章——分析C语言的声明

    前面一章我们已经说过C语言存在的一些问题和它晦涩的地方,让我们对这门神奇的语言有了更深的了解.现在这一章则集中精力来讨论C语言的声明,分为三块,首先是说明C语言声明晦涩难懂的原因和声明是如何形成的,其 ...

  4. 基于Spark和SparkSQL的NetFlow流量的初步分析——scala语言

    基于Spark和SparkSQL的NetFlow流量的初步分析--scala语言 标签: NetFlow Spark SparkSQL 本文主要是介绍如何使用Spark做一些简单的NetFlow数据的 ...

  5. 以杨辉三角为例,从内存角度简单分析C语言中的动态二维数组

    学C语言,一定绕不过指针这一大难关,而指针最让人头疼的就是各种指向关系,一阶的指针还比较容易掌握,但一旦阶数一高,就很容易理不清楚其中的指向关系,现在我将通过杨辉三角为例,我会用四种方法从内存的角度简 ...

  6. AI 的下一个重大挑战:理解语言的细微差别

    简评:人类语言非常博大精妙,同一句话在不同的语境下,就有不同的含义.连人类有时候都不能辨别其中细微的差别,机器能吗?这就是人工智能的下一个巨大挑战:理解语言的细微差别.本文原作者是 Salesforc ...

  7. 框架源码系列四:手写Spring-配置(为什么要提供配置的方法、选择什么样的配置方式、配置方式的工作过程是怎样的、分步骤一个一个的去分析和设计)

    一.为什么要提供配置的方法 经过前面的手写Spring IOC.手写Spring DI.手写Spring AOP,我们知道要创建一个bean对象,需要用户先定义好bean,然后注册到bean工厂才能创 ...

  8. 32 Profiling Go Programs 分析go语言项目

    Profiling Go Programs  分析go语言项目 24 June 2011 At Scala Days 2011, Robert Hundt presented a paper titl ...

  9. 18 A GIF decoder: an exercise in Go interfaces 一个GIF解码器:go语言接口训练

    A GIF decoder: an exercise in Go interfaces  一个GIF解码器:go语言接口训练 25 May 2011 Introduction At the Googl ...

随机推荐

  1. 【ZZ】Java : 一个帝国的诞生 & 假如时光能够倒流, 我会这么学习Java

    Java : 一个帝国的诞生 http://dy.qq.com/article.htm?id=20160523A06XFS00 写的很有意思,一下子了解了JAVA的历史. 假如时光能够倒流, 我会这么 ...

  2. Android中常用适配器及定义自己的适配器

    转载:http://blog.chinaunix.net/uid-11898547-id-3303153.html http://www.tudou.com/home/_328390108/item ...

  3. 小米2s使用Hexamob Recovery PRO恢复数据

    这东西对于手机来说, 真是神器啊 现在很多手机都是以MTP连接到电脑的, 所以在PC上是看不到盘符, 也就无法使用finaldata 之类的工具恢复了. 而像小米2S这样的手机, 无法外接SD卡, 则 ...

  4. 小白日记29:kali渗透测试之Web渗透-扫描工具-Vega

    WEB扫描工具-Vega 纯图形化界面,Java编写的开源web扫描器.两种工作模式:扫描模式和代理模式[主流扫描功能].用于爬站.处理表单,注入测试等.支持SSL:http://vega/ca.cr ...

  5. Object-c中的属性和成员变量的关系详解

    很多人在初学移动开发的时候会对object-c中的合成存取方法感到疑惑,此处尝试为看到本文有缘人答疑解惑,鄙人才疏学浅,难免有疏漏谬误之处,热烈欢迎诸位看官拍砖指点. 1.合成存取方法: OC为增加开 ...

  6. vs中两张图片的融合

    这个其实就是从csdn上面下载的一个例程.感谢这位同学的总结,与源码的有偿分享. 本随笔就是把它通过4个随笔的拆分,实现的. 可以通过: http://blog.csdn.net/masibuaa/a ...

  7. 魔方阵算法及C语言实现

    1 魔方阵概念 填充的,每一行.每一列.对角线之和均相等的方阵,阶数n = 3,4,5….魔方阵也称为幻方阵. 例如三阶魔方阵为: 魔方阵有什么的规律呢? 魔方阵分为奇幻方和偶幻方.而偶幻方又分为是4 ...

  8. Redis中的关系查询(范围查询,模糊查询等...)

    本文部分转自于:http://blog.csdn.net/dc_726/article/details/42784317 本文对Redis如何保存关系型数据,以及如何对其匹配.范围.模糊查询进行举例讲 ...

  9. [改善Java代码]易变业务使用脚本语言编写

    建议16: 易变业务使用脚本语言编写 Java世界一直在遭受着异种语言的入侵,比如PHP.Ruby.Groovy.JavaScript等,这些“入侵者”都有一个共同特征:全是同一类语言—脚本语言,它们 ...

  10. Android之Android studio安装

    首先下载jdk:http://www.oracle.com/technetwork/java/javase/downloads/index.html 然后下载Android SDK:http://ww ...