再探再报 除 0 这件事有不同

首先,在数学中,一个数除以0是没有意义的。

其次,在计算机中,对于除零,传统概念里是会上报一个异常。首先是CPU内部实现会报异常。最早学组成原理和汇编的时候,都是说CPU寄存器中有个表示除零异常的位。在Linux系统中,除零也会出现异常。为了简单期间,我们从应用层来看。

如果代码里直接出现除零,编译器是会报警告的:

当然,我们可以规避这一点,将常量0换成一个表达式。这时候欺骗过了编译器,执行时会上报浮点异常:

不过这样做的前提是整型数。浮点数由于内部表示的差异,可能不会出现真正的除零(即使写直接写0.0,结果也是无穷 inf)。这里就不再展开说明了。

不过最近,博主遇到了一件奇怪的事,在review代码的时候,发现了除零的情况,但是实际运行时,并没有上报异常,当然执行结果也是不对的。

不过博主是在ARM平台上调试的,难道这跟x86有不同?后来实验了一下,本质上二种平台是一致的。ARM中也会提供处理异常的向量,操作系统注册后,遇到处理,就会进入异常处理,类似中断处理的过程。这其实是操作系统底层的处理方法。而博主实测的环境又有所不同,主要是没有使用操作系统,跑的是裸机程序。可是转念一想,也不对啊,即使是裸机方式,也是使用了CPU厂家提供的BSP,其中对异常是有定义的。为了摸清这个问题,不得已再上汇编,看看到底执行指令的情况是啥样的,省得想的头疼。

不看不知道,一看吓一跳。汇编代码里,对除零做了特殊处理,如下图:

汇编后的代码逻辑变成了这样:首先判断除数是否为零,如果是零,就跳到新的位置进行处理。在新的位置,判断被除数与零的大小,如果大于,则将0x80000000取反返回,否则,将其返回。大概意思是,如果被除数大于零,返回最大正数,当前32位系统,就是2,147,483,647,否则,返回最小负数,当前32位系统,就是-2,147,483,648。

有了上面的汇编作支撑,程序没有报异常,也就可以很好的理解了。

从这个例子,还有之前博主测试发现关于堆栈的增长反向的例子(实践出真知--你的字节对齐和堆栈认知可能是错误的_gdb查看字节对齐-CSDN博客),可以看出,计算机领域,很多工程结论是有前提条件的,尤其是在语言、编译器、操作系统、CPU平台存在多种选择的情况下。如果实际工程中遇到了奇怪的问题,并且怀疑是一些基础概念的话,可以做个简单验证,加以快速排除疑惑。这其中的关键就是要意识到很多东西是依赖语言本身特性、编译器实现、操作系统处理方法、CPU支持情况来综合决定的。这也是为啥标准统一显得重要的原因了。

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙赤子

你的小小鼓励助我翻山越岭

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值