找回密码
 立即注册
查看: 77|回复: 6

keil C计算结果不一样,unsigned int A1;unsigned char B2; float y=0; y=A1*B2

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:6
  • 最近打卡:2025-10-20 10:11:44

6

主题

9

回帖

92

积分

注册会员

积分
92
发表于 2025-10-17 09:53:18 | 显示全部楼层 |阅读模式
KC      V5.25.3.0版本,       STC32G8K64

两段程序,输出结果不一样


程序段1:

unsigned int A1;
unsigned char B2;   
float y=0;
unsigned int AABB;
               
A1=3000;
B2=32;       
y=A1*B2;//
       
y=(y/180);
AABB=y;
       

//输出结果AABB=0x00A9.

程序段2:

unsigned int A1;
unsigned char B2;   
float y=0;
unsigned int AABB;
               
A1=3000;
B2=32;       
y=(float)A1*(float)B2;//只有这里用(float)或者(unsigned long)强制转换,结果才真确
       
y=(y/180);
AABB=y;

//输出结果AABB=0x0215.  正确
回复

使用道具 举报 送花

3

主题

1849

回帖

546

积分

等待验证会员

积分
546
发表于 2025-10-17 09:58:00 | 显示全部楼层

关于 Keil C 中 unsigned int 与 unsigned char 运算结果差异的分析

在使用 Keil C 编译器进行嵌入式开发时,尤其是针对 STC32G8K64 等国产 32 位 MCU(基于 Cortex-M0/M4 内核)时,开发者常常会遇到变量类型转换与浮点运算精度相关的问题。本文将结合用户提供的两段代码,分析为何在相同变量赋值、不同表达式写法的情况下,AABB 的最终结果会不同。

一、问题描述

用户提供了两段代码,分别如下:

程序段1:
  1. c
  2. unsigned int A1;
  3. unsigned char B2;   
  4. float y=0;
  5. unsigned int AABB;
  6. A1=3000;
  7. B2=32;       
  8. y=A1B2;
  9. y=(y/180);
  10. AABB=y;
复制代码

输出结果为:AABB = 0x00A9(十进制为 169)

程序段2:
  1. c
  2. unsigned int A1;
  3. unsigned char B2;   
  4. float y=0;
  5. unsigned int AABB;
  6. A1=3000;
  7. B2=32;       
  8. y=(float)A1(float)B2;
  9. y=(y/180);
  10. AABB=y;
复制代码

输出结果为:AABB = 0x0215(十进制为 533),这是预期的正确结果

二、问题分析

1. 类型提升与隐式转换机制

C语言在进行混合类型运算时,会根据类型提升规则(Usual Arithmetic Conversions)对操作数进行自动类型转换。对于表达式:
  1. c
  2. y = A1  B2;
复制代码

其中:
A1 是 unsigned int
B2 是 unsigned char
y 是 float

在 Keil C 编译器中(V52530 版本),unsigned char 在参与表达式计算时,会被提升为 int 类型(即有符号 int),而非 unsigned int。这是 C90/C99 标准中的规定:small integer types(如 char、short)在表达式中会被提升为 int。

因此,表达式 A1  B2 实际上等价于:
  1. c
  2. (int)A1  (int)B2
复制代码

因为 A1 被视为 int,而 B2 也被提升为 int,所以整个乘积的结果也是 int 类型。在 32 位系统中,int 是 32 位有符号整型。

2. 溢出与截断问题

当执行 A1 = 3000, B2 = 32 时:
正确结果应为:3000  32 = 96000
如果 A1  B2 被视为 int 类型运算,那么 96000 超出了 int 类型的正数范围(假设 int 是 16 位,范围为 -32768 ~ 32767),则会发生溢出。

但在 STC32G8K64 平台上,int 是 32 位的,因此不会溢出。但问题出在:表达式结果仍然是整数类型,再赋值给 float 时才转换为 float,这就导致了精度丢失和中间结果不准确。

3. 浮点运算的正确方式

在程序段2中,用户使用了强制类型转换:
  1. c
  2. y = (float)A1  (float)B2;
复制代码

这样确保了两个操作数都被转换为 float 类型,乘法运算也在浮点数域中进行,避免了整数提升和溢出问题,从而得到了正确的中间结果。

三、AABB 的赋值问题

在两个程序段中,最终都执行了:
  1. c
  2. AABB = y;
复制代码

由于 y 是 float 类型,而 AABB 是 unsigned int,此时会进行隐式类型转换。但需要注意:
如果 y 的值超出了 unsigned int 的表示范围(0 ~ 65535,假设为 16 位系统),则行为是未定义的。
在程序段1中,由于 y = A1  B2 实际是 int 类型的乘积(可能溢出或被截断),再赋值给 float,可能导致精度丢失,最终 y 的值是错误的。

四、验证与计算过程

正确计算过程(程序段2):
  1. c
  2. A1 = 3000;
  3. B2 = 32;
  4. y = (float)3000  (float)32 = 96000.0f;
  5. y = 96000.0f / 180 = 533.333...f;
  6. AABB = (unsigned int)y = 533;
复制代码

十六进制表示为:0x0215

错误计算过程(程序段1):
  1. c
  2. A1 = 3000;
  3. B2 = 32;
  4. // A1 和 B2 被当作 int 类型相乘
  5. int temp = 3000  32 = 96000;
  6. // 但 temp 被赋值给 float,可能因精度丢失变为 96000.0f
  7. y = 96000.0f / 180 = 533.333...f;
  8. AABB = y = 533;
复制代码

那为何程序段1输出为 0x00A9(即 169)?

这说明在程序段1中,A1  B2 的中间结果并非 96000,而是发生了某种错误的类型转换或溢出。推测原因如下:
如果 int 是 16 位有符号类型,则 3000  32 = 96000 > 32767,会导致溢出。
溢出后的结果为负数(如 -32768 + (96000 - 32768) = 30768),然后被赋值给 float,最终结果为负数除以 180,可能变成负数或极小正数。
当负数赋值给 unsigned int 时,会进行无符号回绕,结果为 0x00A9(169)。

五、建议与解决方案

为避免此类问题,建议开发者在进行混合类型运算时,采取以下措施:

1. 显式类型转换:在涉及不同类型运算时,使用 (type) 显式转换,确保运算在期望类型下进行。
2. 避免整数溢出:使用 long 或 unsigned long 类型进行大整数运算,或直接使用 float 或 double。
3. 启用编译器警告:Keil 编译器支持 -Wall 等选项,可开启类型转换警告,帮助发现潜在问题。
4. 使用 volatile 修饰符调试:用于调试中间变量,防止编译器优化导致结果异常。

六、结论

程序段1与程序段2结果不同,根本原因在于:
程序段1中,A1  B2 被当作 int 类型相乘,可能因类型提升或溢出导致结果错误;
程序段2中,使用了 (float) 强制类型转换,使乘法运算在浮点域中进行,保证了精度和正确性。

因此,在涉及混合类型运算时,尤其是涉及浮点数的表达式,务必进行显式类型转换,以避免编译器默认类型提升规则带来的不确定性。

作者:国芯人工智能助手  
平台:Keil C V52530 | MCU:STC32G8K64  
时间:2025年04月

[本文内容由国芯人工智能辅助生成,仅供参考]
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:599
  • 最近打卡:2025-10-30 07:14:21
已绑定手机

87

主题

6407

回帖

1万

积分

超级版主

积分
12064
发表于 2025-10-17 10:49:47 | 显示全部楼层
3000*32=96000,大于65535,改为3000UL和32UL
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:6
  • 最近打卡:2025-10-20 10:11:44

6

主题

9

回帖

92

积分

注册会员

积分
92
发表于 2025-10-17 14:15:18 | 显示全部楼层
程序1
unsigned int A1;
unsigned char B2;         
float y=0;
unsigned int AABB;       
A1=3000;
B2=32;       

y=(float)A1*(float)B2;
y=y/180;
AABB=10*y;
       
//求AABB结果=0x14D5,结果正确

程序段2:在程序1基础上,将A1=3000,改成A1=1000,计算结果错误

unsigned int A1;
unsigned char B2;         
float y=0;
unsigned int AABB;       
A1=1000;
B2=32;       

y=(float)A1*(float)B2;
y=y/180;
AABB=10*y;
       
//计算AABB结果=0x07F1,结果错误,正确结果是0x06F1
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:6
  • 最近打卡:2025-10-20 10:11:44

6

主题

9

回帖

92

积分

注册会员

积分
92
发表于 2025-10-17 15:21:23 | 显示全部楼层
求C251 keil c软件
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:6
  • 最近打卡:2025-10-20 10:11:44

6

主题

9

回帖

92

积分

注册会员

积分
92
发表于 2025-10-17 16:29:43 | 显示全部楼层
求好心人,重新编译以下,发上来,
感觉是编译器问题,

C语言(浮点计算).zip

47.37 KB, 下载次数: 1

回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:6
  • 最近打卡:2025-10-20 10:11:44

6

主题

9

回帖

92

积分

注册会员

积分
92
发表于 2025-10-17 17:10:04 | 显示全部楼层
刚才,换了一个单片机,又正常,10个板,发现2个不正常,都是计算错误
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-10-30 22:03 , Processed in 0.139938 second(s), 85 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表