波特律动
课程中心/51单片机教程/【C语言】数据运算

【C语言】数据运算

在C语言(Keil C51 ) 中,“数据运算”有以下几类:

一、算术运算

1. 加减乘除 取余

运算

运算符

示例

结果

加法

+

7 + 3

10

减法

-

7 - 3

4

乘法

*

7 * 3

21

除法

/

7 / 3

2

取余

%

7 % 3

1

算术运算
C语言
1unsigned char a = 7;
2unsigned char b = 3;
3
4unsigned char sum = a + b; // 10
5unsigned char difference = a - b; // 4
6unsigned char product = a * b; // 21
7unsigned char quotient = a / b; // 2
8unsigned char remainder = a % b; // 1

需要注意:

  • 两个整数相除,结果仍然是整数,小数部分会被舍去。
  • % 主要用于整数取余,浮点数取余应使用 fmod()
  • 除数不能为 0
  • C 语言里的 ^ 不是乘方,而是按位异或。乘方需要使用 pow()

2. 正号与负号

运算

运算符

示例

保持正值

+

a = +b;

改变正负

-

a = -b;

正负号
C语言
1int a = 10;
2int b = -a; // b = -10

3. 自增与自减

运算

运算符

示例

含义

自增

++

a++ ++a

a 增加 1

自减

--

a-- --a

a 减少 1

C语言
1unsigned char a = 7;
2unsigned char b;
3
4a++; // a = 8
5a--; // a = 7
6
7++a; // a = 8
8--a; // a = 7
9
10b = a++; // 先是 b = 7 然后 a = 8
11b = a--; // 先是 b = 8 然后 a = 7
12
13b = ++a; // 先是 a = 8 然后 b = 8
14b = --a; // 先是 a = 7 然后 b = 7

单独使用时,a++++a 都会让 a 增加 1;放在表达式中时,两者计算顺序不同。

二、二进制 按位运算

1. 按位与 &

a & b 将两个数据的每一位进行“与”操作:当二者此位都是 1,则结果的此位是 1,否则为 0。


按位与 计算示意
纯文本
1 0000 1100
2& 0000 1010
3------------
4 0000 1000

按位与 常用于清零某些位、提取某些位。


比如下述操作清零了 a 的高 4 位,提取了 a 的低 4 位

unsigned char a = 0xAA; // 10101010;

a = a & 0x0F; // 0x0A 00001010


2. 按位或 |

a | b 将两个数据的每一位进行“或”操作:当二者此位任意一个是 1,则结果的此位是 1,否则为 0。


按位或 计算示意
纯文本
1 0000 1100
2| 0000 1010
3------------
4 0000 1110

按位或 常用于将某些位 置 1


比如下述操作 将 a 的第 7 位设置为了1


unsigned char a = 0x0A; // 0000 1010

// (0x80 是 1000 0000)

a = a | 0x80; // 0x8A 1000 1010


3. 按位异或

a ^ b 将两个数据的每一位进行“异或”操作:当二者此位有且只有一个是 1,则结果的此位是 1,否则为 0。

按位异或 计算示意
纯文本
1 0000 1100
2^ 0000 1010
3------------
4 0000 0110

按位异或 常用于将某些位 翻转


比如下述操作 将 a 和 b 的第 0 位 进行了翻转


unsigned char a = 0xAA; // 1010 1010

unsigned char b = 0xAB; // 1010 1011

a = a ^ 0x01; // 0xAB 1010 1011

b = b ^ 0x01; // 0xAA 1010 1010

4. 按位取反

~a 将数据的每一位都取反,0变1,1变0;

按位取反 计算示意
纯文本
10000 1100
2取反
31111 0011

三、二进制 移位运算

1. 左移

a << n 将所有二进制位向左移动 n 位,右侧补 0,左侧移出去的数据丢失。

左移 计算示意
纯文本
1a = 0010 1101
2
3a << 4:
4
51101 0000

对于没有发生溢出的无符号整数,左移一位通常相当于乘以 2


unsigned char a = 3; // 0000 0011

a = a << 1; // 6 0000 0110

2. 右移

a >> n 将所有二进制位向右移动 n 位,左侧补 0,右侧移出去的数据丢失。


右移 计算示意
纯文本
1a = 0010 1101
2
3a >> 4:
4
50000 0010

对于无符号整数,右移一位通常相当于除以 2。进行移位和掩码操作时,建议优先使用 unsigned charunsigned int 等无符号类型,避免符号位带来的影响。

3. 循环左移 循环右移

循环位移函数由Keil C51 提供的,普通移位会丢弃被移出去的二进制位,而循环移位会把移出去的数据重新放到另一端。

函数

作用

_crol_()

unsigned char 循环左移

_cror_()

unsigned char 循环右移

_irol_()

unsigned int 循环左移

_iror_()

unsigned int 循环右移

_lrol_()

unsigned long 循环左移

_lror_()

unsigned long 循环右移

函数名称中的 cil 分别代表 unsigned charunsigned intunsigned long , ro 代表循环,lr 分别代表 左 和 右。


循环移位 计算示意
纯文本
1a = 1000 0001
2
3a = _crol_(a, 1);
4
5结果为 0000 0011

四、比较运算

比较运算用于比较两个数据的大小或是否相等。

运算

运算符

示例

等于

==

a == b

不等于

!=

a != b

大于

>

a > b

小于

<

a < b

大于等于

>=

a >= b

小于等于

<=

a <= b

比较运算一般用于判断
C语言
1if (a >= 10)
2{
3 // a大于或等于10
4}

注意不要把判断相等的 == 写成赋值运算符 =

五、逻辑运算

逻辑运算通常用于组合多个判断条件。

运算

运算符

含义

逻辑与

&&

两个条件都成立

逻辑或

||

两个条件至少有一个成立

逻辑非

!

条件取反

C语言
1if ((a > 0) && (a < 10))
2{
3 // a大于0并且小于10
4}
5
6if ((a == 1) || (b == 1))
7{
8 // 至少有一个条件成立
9}
10
11if (!a)
12{
13 // a等于0时成立
14}


六、复合赋值运算

复合赋值就是“完成一次运算,并把结果重新存入变量”。

运算符

等价写法

a += b

a = a + b

a -= b

a = a - b

a *= b

a = a * b

a /= b

a = a / b

a %= b

a = a % b

a &= b

a = a & b

a |= b

a = a |b

a ^= b

a = a ^ b

a <<= b

a = a << b

a >>= b

a = a >> b

七、条件运算符

条件运算符也叫三目运算符:条件 ? 结果1 : 结果2,如果条件成立,则返回结果1,如果条件不成立,则返回结果2。


三目运算符 计算逻辑
C语言
1max = (a > b) ? a : b;
2// 等价于
3if (a > b) {
4 max = a;
5}
6else {
7 max = b;
8}

八、强制类型转换

强制类型转换 可以在计算过程中将某个类型的数据强制当做另一种类型的数据处理。

强制类型转换 使用案例
C语言
1unsigned char a = 7;
2unsigned char b = 2;
3float result;
4
5result = a / b; // 结果是 3,因为整数除法,结果只保留整数
6result = (float)a / b; // 结果是 3.5,因为此时 a 当做浮点数,因而进行的是浮点数除法


九、常用数学函数

大多数数学函数需要包含#include <math.h>

1. 绝对值

函数

作用

abs()

int 绝对值

labs()

long 绝对值

fabs()

求浮点数绝对值

求绝对值函数
C语言
1int a = abs(-10); // 10
2long b = labs(-1000L); // 1000
3float c = fabs(-3.14); // 3.14

2. 取整

函数

作用

ceil()

向上取整

floor()

向下取整

取整函数
C语言
1float a = ceil(3.2); // 结果:4.0
2float b = ceil(3.8); // 结果:4.0
3float c = ceil(-3.2); // 结果:-3.0
4
5float a = floor(3.2); // 结果:3.0
6float b = floor(3.8); // 结果:3.0
7float c = floor(-3.2); // 结果:-4.0

需要注意,向上和向下是按照数轴方向判断的,并不是简单地去掉小数部分。

3. 浮点数取余

浮点数不能使用 %取余,可以使用 fmod()


浮点数取余
C语言
1float a = fmod(7.5, 2.0); // 结果:1.5
2float b = fmod(8.0, 3.0); // 结果:2.0

4. 平方根

sqrt(x) 用于计算一个数的平方根。


平方根
C语言
1float a = sqrt(16.0); // 结果:4.0
2float b = sqrt(25.0); // 结果:5.0
3float c = sqrt(2.0); // 结果:约1.414
4
5// 通常不能对负数进行普通的平方根运算:
6
7float a = sqrt(-1.0); // 结果:无效浮点数

5. 乘方运算

pow(x, y) 用于计算 xy 次方。

乘方运算
C语言
1float a = pow(2.0, 3.0); // 结果:8.0
2float b = pow(10.0, 2.0); // 结果:100.0
3float c = pow(9.0, 0.5); // 结果:3.0

需要注意,C 语言中的 ^ 不是乘方运算,而是按位异或

6. 三角函数

函数

作用

sin()

计算正弦值

cos()

计算余弦值

tan()

计算正切值

这些函数接收的角度单位是弧度,而不是通常使用的角度。


三角函数
C语言
1#define PI 3.1415926
2
3float a = sin(PI / 2); // 结果:约1.0
4float b = cos(0); // 结果:1.0
5float c = tan(PI / 4); // 结果:约1.0
6
7如果已知的是角度,可以先转换成弧度:
8
9#define PI 3.1415926
10
11float angle = 90.0;
12float radian = angle * PI / 180.0; // 结果:约1.5708
13float value = sin(radian); // 结果:约1.0

7. 反三角函数

函数

作用

asin()

反正弦

acos()

反余弦

atan()

反正切

atan2()

根据横纵坐标计算方向角

反三角函数
C语言
1#define PI 3.1415926
2
3float a = asin(1.0); // 结果:约1.5708弧度,也就是90°
4float b = acos(0.0); // 结果:约1.5708弧度,也就是90°
5float c = atan(1.0); // 结果:约0.7854弧度,也就是45°
6float d = atan2(1.0, 1.0); // 结果:约0.7854弧度,也就是45°
7
8将弧度转换成角度:
9
10#define PI 3.1415926
11
12float radian = atan(1.0); // 结果:约0.7854弧度
13float angle = radian * 180.0 / PI; // 结果:约45.0°

8. 指数和对数

函数

作用

exp()

计算以 e 为底的指数

log()

计算以 e 为底的对数

log10()

计算以 10 为底的对数。

指数和对数
C语言
1exp():计算以 e 为底的指数
2float a = exp(0.0); // 结果:1.0
3float b = exp(1.0); // 结果:约2.718
4float c = exp(2.0); // 结果:约7.389
5log():计算自然对数
6
7log() 计算的是以 e 为底的对数。
8
9float a = log(1.0); // 结果:0.0
10float b = log(2.71828); // 结果:约1.0
11log10():计算常用对数
12
13log10() 计算的是以 10 为底的对数。
14
15float a = log10(10.0); // 结果:1.0
16float b = log10(100.0); // 结果:2.0
17float c = log10(1000.0); // 结果:3.0
18
19对数函数的参数必须大于 0
20
21float a = log(0.0); // 结果:无效或趋近负无穷
22float b = log(-1.0); // 结果:无效浮点数

9. 随机数

rand() 用于产生一个伪随机整数。

随机数
C语言
1unsigned int a = rand(); // 结果:一个伪随机整数
2
3可以使用 % 限制随机数范围:
4
5unsigned int a = rand() % 10; // 结果:0~9之间的整数
6unsigned int b = rand() % 6 + 1; // 结果:1~6之间的整数
7unsigned int c = rand() % 100 + 1; // 结果:1~100之间的整数
8
9srand() 可以设置伪随机数的种子:
10
11srand(123); // 结果:设置随机数种子为123
12unsigned int a = rand(); // 结果:由当前C51库实现决定的伪随机数
13
14使用相同的种子,通常会产生相同的伪随机数序列。

注意事项

51 单片机通常没有专门的浮点运算硬件,因此下面这些函数主要通过软件完成:

sqrt(); pow(); sin(); cos(); tan(); log();

它们虽然使用方便,但会增加程序体积,并占用较多运算时间。

因此,在普通的 51 单片机程序中:

  • 简单计算优先使用整数运算。
  • 乘以或除以 2 的整数次幂,可以考虑移位运算。
  • 三角函数和开方运算尽量不要放在高频循环或中断函数中。
  • 对运算速度要求较高时,可以使用查表法或定点数运算。