ifare 发表于 2022-3-22 16:39:01

请教KEIL5中的一个C语言运算问题

         通过下面两个简单的算式给ltemp 赋值, 减9*3600的运算结果是正确的,减10*3600的结果就不对,请大侠指点一下是什么原因。

          UINT32 ltemp=0;

          ltemp = 70000-9*3600;       //37600    //正确
          ltemp = 70000-10*3600;   //99536    //错误

cddxhy 发表于 2022-3-22 16:41:18

ltemp = 70000L-10L*3600L; //L可能是大小写

vuo50z 发表于 2022-3-22 16:42:41

应该是溢出问题,不同mcu体系下int的长度不一样

2nd 发表于 2022-3-22 17:31:56

#include <stdio.h>
#include <stdint.h>

int main()
{
    uint32_t ltemp = 0;
    int16_t ltemp1 = 9 * 3600;
    ltemp = 70000 - ltemp1;       //37600    //正确
    printf("%d", ltemp);
    ltemp1 = 10 * 3600;
    ltemp = 70000 - ltemp1;   //99536    //错误
    printf(" %d", ltemp);
    return 0;
}
输出:
37600 99536

t3486784401 发表于 2022-3-22 18:10:11

2nd 发表于 2022-3-22 17:31
输出:
(引用自4楼)

9*3600 = 32400,int16 装得下;
10*3600 = 36000,int16 装不下,溢出为 -29536

所以你再用 70000 去减,就出九万多

1a2b3c 发表于 2022-3-22 18:16:45

楼主不是int32吗,怎么会错呢,

t3486784401 发表于 2022-3-22 18:21:23

1a2b3c 发表于 2022-3-22 18:16
楼主不是int32吗,怎么会错呢,
(引用自6楼)

int32 只是不出错的必要条件

1a2b3c 发表于 2022-3-22 18:26:22

嗯,但是表面上看起来他的应该是没有啥问题,任何一项减数被减数都没有溢出,我是搞不懂了,要是电脑在身边我就马上建个工程试下了

armstrong 发表于 2022-3-22 18:33:40

t3486784401 真是厉害!
C51而言,等式右边不可能自动提升为UINT32的,顶多提升为unsigned int型,是16位无符号。
除非显示转换:
ltemp = 70000ul-10ul*3600ul; //假如ul后缀代表unsigned long的话。

ehengio 发表于 2022-3-22 22:00:01

在不考虑自动整形提升的情况下,10是s8,3600是s16,两者相乘结果为s16。36000超s16的最大值32767,所以出错。

2nd 发表于 2022-3-22 22:26:24

本帖最后由 2nd 于 2022-3-22 22:33 编辑

如我前面逆向写的代码,楼主的编译器int型是16位的,大家理解下这个点。
编辑说明:补充用例,ltemp1增加类型转换
#include <stdio.h>
#include <stdint.h>

int main()
{
    uint32_t ltemp = 0;
    int16_t ltemp1 = 9 * 3600;
    ltemp = 70000 - ltemp1;       //37600    //正确
    printf("%d", ltemp);
    ltemp1 = 10 * 3600;
    ltemp = 70000 - (uint16_t)ltemp1;   //99536    //错误
    printf(" %d", ltemp);
    return 0;
}
输出:
37600 34000

laujc 发表于 2022-3-23 07:22:13

LZ用的哪个型号的单片机?

初音之恋 发表于 2022-3-23 08:46:25

10*3600刚好运算溢出,你这里9和3600都是int16类型,乘出来的结果也是int16,可以改成9.0*3600提升到双精度类型再最后转换回来

gonboy 发表于 2022-3-23 08:56:03

典型的类型与编译器/单片机型号的问题。 1. 先测试下 uint32,到底是多少位? 2. 测试下右侧纯数字多大溢出。 就知道问题了

R88 发表于 2022-3-23 09:07:05

1a2b3c 发表于 2022-3-22 18:26
嗯,但是表面上看起来他的应该是没有啥问题,任何一项减数被减数都没有溢出,我是搞不懂了,要是电脑在身边 ...
(引用自8楼)

我试验了,正好手上的pic单片机是16位结果如楼主一样。一步一步debug的,看得变量值就跟楼主一样,下面是改为正确的:

TEMP = 70000-10U*3600U;   或者TEMP = 70000-10*3600U; 都是正确的。

ifare 发表于 2022-3-27 09:16:53

用的单片机信号型号是N76E003。谢谢上面的各位坛友,已采用在3600后面加U的方式解决。百度了一下,在keil中U和UL后缀都是指“unsigned long ”。

cc1987 发表于 2022-3-27 13:59:37

{:lol:}有坑 需要注意
页: [1]
查看完整版本: 请教KEIL5中的一个C语言运算问题