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

 #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. ${var}变量替换

    ${age},${name} 给定一个上下文 Map<String,String> context 使用上下文替换变量private static final Pattern VAR_PA ...

  2. java_SSH整合1

    Domain: public class Department { private Long id; private Set<User> users = new HashSet<Us ...

  3. 最简单的Java调用C/C++代码的步骤

    1)首先在Java类中声明一个native的方法 (2)使用javah命令生成包含native方法声明的C/C++头文件 (3)按照生成的C/C++头文件来写C/C++源文件 (4)将C/C++源文件 ...

  4. wpf linq数据库无法插入

    最近做wpf应用程序,遇到一个很奇怪的问题,我用代码往数据库里插入数据成功了,但去vs的服务器资源管理器里查看数据库总是最开始的样子,什么都没有插入进去,然后就检查代码,打日志查看sql语句,发现都没 ...

  5. spring4.x注解概述

    1. 背景 注解可以减少代码的开发量,spring提供了丰富的注解功能,因项目中用到不少注解,因此下定决心,经spring4.x中涉及到的注解罗列出来,供查询使用. 2. spring注解图     ...

  6. vim替换命令

    转载:http://blog.csdn.net/glorin/article/details/6317098 替換(substitute) :[range]s/pattern/string/[c,e, ...

  7. org.apache.hadoop.fs-BufferedFSInputStream

    封装了FSInputStream package org.apache.hadoop.fs; import java.io.BufferedInputStream; import java.io.IO ...

  8. LXNetwork – 基于AF3.0封装的iOS网络请求库

    本框架实现思路与YTKNetwork和RTNetworking类似,相当于一个简单版,把每一个网络请求封装成对象.使用LXNetwork,你的每一个请求都需要继承LXBaseRequest类,通过覆盖 ...

  9. ActiveXObject对象详解

    一.什么是 ActiveX 控件?         ActiveX 控件广泛用于 Internet.它们可以通过提供视频.动画内容等来增加浏览的乐趣.不过,这些程序可能出问题或者向您提供不需要的内容. ...

  10. 代理和 block 传值的使用

    // // ZYViewController.h // BlockTest // // Created by yejiong on 14/11/2. // Copyright © 2014年 zzz. ...