1除以0等于几

调试时遇到一段代码,精简后如下:

double val = 1 / (0 * 1.0);
uint32_t result = (uint32_t) val;

在Keil环境下(armcc v5.06)下,变量val = 0,result = 0,在Gcc环境下(arm-none-eabi-gcc v6.3.1)下,val = Inf(一个很大的数),result = 0xFFFFFFFF。

除法运算,除数不能为0。如果除数为0,该行为未定义(Undefined):

C99 6.5.5p5 – The result of the / operator is the quotient from the division of the first operand by the second; the result of the % operator is the remainder. In both operations, if the value of the second operand is zero, the behavior is undefined. [link]

实践中,如果被除数是0,编译器会给出警告(Warning),但是上面代码里( 0 * 1.0 )的操作骗过了编译器的检查。

于是,Keil和Gcc两个不同平台的编译器给出了不同的结果。

猜测虽然C语言的规范没有定义,但具体到编译器身上,还是要给出一个数值结果——Keil给0,Gcc给Inf。

这种基础运算经常出现在库函数里不起眼的角落,并且会被重重嵌套。这个例子背后真实的代码是Thingy52里面sx1509的驱动代码[link]:

uint32_t fade_in_time_low_mult_reg = 
(uint32_t) round(
        (real_val->fade_in_time_ms /
        (REG_RISEFALL_TIME_LOW_MULTIPLIER *
        (reg_val->on_intensity - (4 * reg_val->off_intensity)) *
        (255 / m_clkx_tics_pr_sec))) / 1000);

这一行代码中涉及到了多种数据类型:uint8_t,整形宏,float,double, uint32_t,此外还有常量。不同类型数据混合运算,会发生隐式类型转换,代码中也同时使用了显式类型转换。这些东西混在一起写成一行,很容易产生BUG。

(完)