首先,在数学中,一个数除以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支持情况来综合决定的。这也是为啥标准统一显得重要的原因了。