从单片机基础到程序框架(全集 2019pdf版).pdf - 第105页
分析: 第 一 步 : unsigned l ong 类 型 的 中 间 变 量 在 转 换 之 前 为 什 么 要 先 赋 值 0 进 行 清 零 , 比 如 上 述 代 码 的 “s=0;”?因 为它是 32 位的 数据类型,它 也是一个 随机数,如 果不清零,后 续的其它类型 的变量可 能是 16 位或 者 8 位的 类型 变 量, 这 些宽 度不 一 的变 量 在给 32 位的 变 量赋 值 的时 候 ,只 能 覆盖 到 3 2…

第二十四节:借用 unsigned long 类型的中间变量可以减少溢出现象。
【24.1 为什么要借用 unsigned long 类型的中间变量?】
为什么要借用 unsigned long 类型的中间变量进行算术运算?其实就是为了减少溢出的问题。溢出是因
为数据超过了它的最大范围,unsigned char ,unsigned int ,unsigned long 三种数据类型中,unsigned long
的取值是最大的。当参与运算变量中存在非 unsigned long 类型的时候,在运算前,先让每个非 unsigned long
类型的变量借用一个 unsigned long 类型的中间变量,然后才开始运算,可以大大减少运算中的溢出问题。
unsigned long 的取值是从 0 到 4294967295,万一数据超过了 4294967295 怎么办?有两种办法,一种是换
更加高级的 32 位单片机,比如 stm32 单片机就支持 64 位长度的“long long”数据类型,64 位长度的数据
类型基本上可以满足绝大多数涉及运算的项目,还有一种方法思路是可以用 BCD 码的数组方式进行运算,这
种数组运算的方法我以后会跟大家介绍,初学者现在暂时不用深入了解它。
【24.2 如何借用 unsigned long 类型的中间变量?】
借用中间变量的方法是引入中间变量,有多少个非 unsigned long 类型变量就引入多少个 unsigned long
中间变量,再借这个“壳”进行运算,最后再把中间变量的计算结果返回给实际变量。请看下面例子。
转换之前:
unsigned int a;
unsigned char x=195;
unsigned long y=101;
a=x-y; //进行算术减法运算
分析:
上述公式用到 3 个变量,其中 a 和 x 都不是 unsigned long 变量,因此需要为它们分别引入两个 unsigned
long 类型的中间变量 t 和 s,于是乎,继续往下看......
转换之后:
unsigned int a;
unsigned char x=195;
unsigned long y=101;
unsigned long t; //引入的中间变量 t,用来给 a 借用。
unsigned long s; //引入的中间变量 s,用来给 x 借用。
//第一步:使用之前先清零
t=0; //t 在用之前,先把 t 的 32 位全部清零。
s=0; //s 在用之前,先把 s 的 32 位全部清零。
s=x; //s 接收 x 原数据,等效于 x 借用 unsigned long 中间变量 s 这个壳。
t=s-y; //此处 unsigned long 类型的 t 就默认代表了 unsigned int 类型的变量 a。
//第二步:因为其它的变量都是临时的,所以运算结束后再返回计算结果给原来的变量。
a=t; //运算结束后再把计算结果返回给原来的变量 a。

分析:
第一步:unsigned long 类型的中间变量在转换之前为什么要先赋值 0 进行清零,比如上述代码的
“s=0;”?因为它是 32 位的数据类型,它也是一个随机数,如果不清零,后续的其它类型的变量可能是 16
位或者 8 位的类型变量,这些宽度不一的变量在给 32 位的变量赋值的时候,只能覆盖到 32 位变量的低 16
位或者低 8 位,无法等效于实际借用者变量的数值,所以有可能会出错。
第二步:因为其它的变量都是临时的,所以运算结束后应该再返回计算结果给原来的实际变量。在这里
要多说一句,实际项目中,最后接收运算结果的变量应该根据项目所需去选择它的类型,建议尽量选择
unsigned long 类型吧,否则,如果中间变量的计算结果大于接收变量本身的类型范围,也会发生溢出。比
如,上述最后一行代码 a=t,如果此时 t 的数值大于 65535,a 也会发生溢出的现象。 但是如果 a 本身是
unsigned long 类型,就不会发生这种现象。
加法,乘法,除法在借用中间变量的时候,跟本节减法例子中的思路也大同小异。
【24.3 建议在算术运算中确保所有的变量都是 unsigned long 类型。】
不管是以前讲的加法,现在讲的减法,还是未来讲的乘法和除法,我都会建议“在加减乘除四则运算中,
凡是非 unsigned long 类型的变量,都应该借用 unsigned long 类型的中间变量进行运算,最后再返回计算
结果给实际的变量。”unsigned long 变量是三种数据类型中取值范围最大的数,借用此类型的中间变量,可
以减少在简单运算中可能出现的溢出问题。

第二十五节:乘法运算中的 5 种常用组合。
【25.1 乘法语法格式。】
乘法语法格式:
“保存变量”=“乘数 1”*“乘数 2”*..*“乘数 N”;
含义:为什么 C 语言的乘法符号并不是我们熟悉的“X”而是“*”?我猜测是因为“X”跟键盘的大写
字母“X”重复有冲突了,而“*”轮廓跟“X”很相似,并且也可以在键盘上通过“Shift+8”的组合键直接
键入“*”,所以用“*”作为乘法符号。上述乘法格式中,右边的“乘数”与“乘数”相乘(这里暂时把平
时所说的被乘数也归类为乘数),并且把最终的运算结果赋值给左边的“保存变量”。注意,这里的符号“=”
不是等于号的意思,而是赋值的意思。左边的“保存变量”必须是变量,不能是常量,否则编译时会报错。
右边的“乘数”既可以是变量,也可以是常量,也可以是“保存变量”本身自己。多说一句,什么是变量和
常量?变量是可以在程序中被更改的,被分配的一个 RAM 空间。常量往往是数字,或者被分配在 ROM 空间的
一个具体数值。下面根据右边“乘数”与“乘数”的不同组合,列出了乘法运算的 5 种常用组合。
第 1 种:“乘数 1”是常量,“乘数 2”是常量。比如:
unsigned char a;
a=15*3;
分析:数字“15”和“3”都是常量。执行上述语句后,保存变量 a 变成了 45。
第 2 种:“乘数 1”是变量,“乘数 2”是常量。比如:
unsigned char b;
unsigned char x=15;
b=x*10;
分析:x 是变量,“10”是常量。由于原来 x 变量里面的数值是 15,执行上述语句后,保存变量 b 变成
了 150。而变量 x 则保持不变,x 还是 15。
第 3 种:“乘数 1”是变量,“乘数 2”是变量。比如:
unsigned char c;
unsigned char x=15;
unsigned char y=6;
c=x*y;
分析:x 是变量,y 也是变量。由于原来 x 变量里面的数值是 15,y 变量里面的数值是 6,执行上述语句
后,保存变量 c 变成了 90。而变量 x 和 y 则保持不变,x 还是 15,y 还是 6。
第 4 种:“乘数 1”是保存变量本身,“乘数 2”是常量。比如:
unsigned char d=18;
d=d*2;
d=d*7;
分析:d 是保存变量,“2”和“7”都是常量。这类语句有一个特点,具备了自乘功能,可以更改自己本
身的数值。 比如原来保存变量 d 的数值是 18,执行“d=d*2;”语句后,d 变成了 36,接着再执行完“d=d*7;”
语句后,d 最后变成了 252。
第 5 种:“乘数 1”是保存变量本身,“乘数 2”是变量。比如: