4、C语言基础回顾(上):数据类型、变量与常量、运算符与表达式、输入输出函数
各位同学,咱们今天开始正式进入C语言的基础回顾。
说实话,我见过不少刚入行的嵌入式工程师,上来就啃寄存器、啃中断,结果连个变量类型都搞混,最后调试到崩溃。我个人习惯是,先把地基打牢。你想想看,轨道车门控制器的代码,一个字节的偏差都可能导致开关门时序错乱,这可不是闹着玩的。
好,咱们开始。
4.1 数据类型:你到底占几个字节?
嵌入式C语言里,数据类型直接决定了你操作的内存大小。我当年在做一个车门状态采集项目时,就因为用了 int 来存一个开关信号,结果在不同编译器下占的字节数不一样,导致数据错位。嗯,这里要注意。
标准C的数据类型,咱们重点掌握这几个:
- char:1字节,-128 ~ 127 或 0 ~ 255(看是否带符号)。我习惯用它来存小范围的状态值,比如车门开/关标志。
- short:2字节,-32768 ~ 32767。适合存计数器。
- int:在8位单片机上通常是2字节,在32位ARM上是4字节。所以,千万别写死长度。
- long:4字节或8字节,看平台。
- float/double:浮点数,嵌入式里尽量少用,因为运算慢。我一般只在做故障诊断的阈值计算时才用。
重要提醒: 在嵌入式开发中,强烈建议使用 stdint.h 里定义的类型,比如 uint8_t、uint16_t、uint32_t。这样代码跨平台时,字节长度是确定的,不会出幺蛾子。
我的小技巧: 定义车门状态时,用 uint8_t door_status; 而不是 int door_status;。省内存,而且一看就知道是8位的状态量。
4.2 变量与常量:你的数据是死的还是活的?
变量,说白了就是内存里的一块空间,你可以往里面写数据,也可以读出来。常量,就是写死了的值,程序运行期间不能改。
定义变量时,我建议你养成一个好习惯:先声明,再使用。而且变量名要见名知意。我曾经接手过一个项目,变量名叫 a、b、c,看得我头皮发麻。
// 好的命名
uint8_t door_open_flag; // 车门打开标志
uint16_t motor_speed_rpm; // 电机转速
// 差的命名
int a; // 谁知道这是啥?
int b; // 猜去吧
常量有两种定义方式:
- #define:预处理阶段替换,不占内存。比如
#define DOOR_OPEN 1 - const:编译阶段处理,占内存,但类型安全。比如
const uint8_t DOOR_OPEN = 1;
我个人习惯,简单的数值宏用 #define,需要类型检查的用 const。你想想看,如果定义了一个 const float 的阈值,编译器会帮你检查类型,不容易出错。
避坑指南: 我曾经在定义车门超时时间时,用了 #define TIMEOUT 5000,结果在另一个文件里不小心重定义了,导致编译报错。后来我改用 const uint16_t TIMEOUT = 5000;,就再没出过这种问题。
4.3 运算符与表达式:让数据动起来
运算符就是C语言里的「动作指令」。咱们嵌入式开发中,最常用的几类:
算术运算符
+、-、*、/、%。注意,整数除法会丢掉小数部分。比如 5 / 2 = 2,不是2.5。我刚开始学的时候,就在这里栽过跟头。
关系运算符
>、<、==、!=。用来比较大小。注意 == 和 = 的区别,写错一个,程序逻辑全乱。我曾经在判断车门是否关紧时,写成了 if (door_status = CLOSED),结果永远为真,车门一直显示关闭状态。嗯,这个坑我记忆犹新。
逻辑运算符
&&(与)、||(或)、!(非)。用来组合条件。比如:
if (door_closed && motor_stopped) {
// 允许开门
}
位运算符
这是嵌入式开发的精髓。&、|、^、~、<<、>>。直接操作寄存器的每一位。
实战案例: 假设你要设置某个寄存器的第3位为1,其他位不变:
REG |= (1 << 3); // 置位第3位
要清除第3位:
REG &= ~(1 << 3); // 清零第3位
你想想看,如果没有位运算,你要怎么操作?用加减法?那效率低得可怕。
4.4 输入输出函数:和硬件打个招呼
在嵌入式里,输入输出函数通常不是标准库里的 printf 和 scanf,而是直接操作寄存器或调用硬件抽象层接口。但为了学习,咱们先用标准库的来理解概念。
printf:输出到控制台
格式化输出。比如:
uint8_t door_count = 3;
printf("当前车门数量: %d\n", door_count);
常用的格式符:%d(整数)、%f(浮点数)、%x(十六进制)、%c(字符)。
我的习惯: 调试时,我经常用 printf 打印关键变量的值。但正式产品里,我会把它关掉,或者用串口输出到调试工具。因为 printf 太占资源了。
scanf:从控制台输入
这个在嵌入式里用得少,因为很少有键盘输入。但理解它的原理很重要:它从标准输入读取数据,按格式解析。
int speed;
scanf("%d", &speed); // 注意 & 符号
这里有个容易犯的错:scanf 需要变量的地址,所以要用 &。我见过不少新手忘了加 &,结果程序直接崩溃。
避坑指南: 在真正的嵌入式项目中,输入输出通常是通过串口中断或DMA来实现的。标准库的 scanf 是阻塞的,会卡死整个系统。所以,千万别在产品代码里直接用 scanf。我当年在调试一个车门控制器时,就因为用了 scanf 等待输入,结果车门开关指令被阻塞,差点出事故。
好了,这一章的内容就到这里。数据类型、变量常量、运算符、输入输出,这些都是C语言的骨架。你把这些搞明白了,后面写代码就会顺手很多。
下一章,咱们继续回顾C语言的控制流和数组。到时候我会结合轨道车门的实际场景,给你讲讲怎么用 if-else 和 switch 来控制车门状态机。
公众号:蓝海资料掘金营,微信deep3321