第1章:基本数据类型与变量

各位同学,咱们今天聊聊C语言里最基础的东西——数据类型和变量。你别看它基础,我做了十几年嵌入式开发,见过太多老手在这上面翻车。说白了,数据就是程序的血液,类型就是血液的标签。标签贴错了,程序跑起来就会出各种怪问题。

1.1 整型(int)——最常用的数据容器

整型,就是用来存整数的。在C语言里,int是最常用的整型类型。但有个坑我得先告诉你:int的字节长度其实跟平台有关。

关键点:在16位系统上,int是2字节;在32位和64位系统上,int通常是4字节。

我在做STM32项目时,就遇到过把int当4字节用,结果移植到16位MCU上直接数据溢出的情况。嗯,那次排查了整整一个下午。

整型还有几个变种:

  • short int(或 short)—— 通常2字节,范围小但省内存
  • long int(或 long)—— 至少4字节,范围更大
  • long long —— C99标准引入,至少8字节

你想想看,如果只是存个年龄,用int就够了。但要是存时间戳,就得用long long。选类型不是越宽越好,得看实际需求。

1.2 浮点型(float/double)——处理小数

浮点型用来表示带小数点的数。C语言提供了两种:

类型 字节数 有效位数 典型范围
float 4 约6-7位 ±1.2E-38 ~ ±3.4E+38
double 8 约15-16位 ±2.3E-308 ~ ±1.7E+308

我个人习惯是:能用double就不用float。为什么?因为float的精度在累加运算中很容易丢失。我曾经在做一个传感器数据滤波算法时,用float累加1000次后,误差已经大到不可接受了。换成double后,问题迎刃而解。

注意:浮点数不能直接用 == 比较相等!因为浮点运算有精度误差。正确的做法是判断两个数的差是否小于一个很小的阈值(比如 0.00001)。

1.3 字符型(char)——不只是字符

char在C语言里是个很有意思的类型。它名义上是字符型,实际上就是个1字节的整数。你完全可以拿它来存小范围的整数。

char ch = 'A';      // 字符A,实际存的是65(ASCII码)
char num = 100;     // 合法!char可以当小整数用
char flag = 0;      // 用来表示开关状态

这里有个细节:char到底是signed还是unsigned,C标准没规定,由编译器决定。我建议你明确写:

signed char   // 范围 -128 ~ 127
unsigned char // 范围 0 ~ 255

我在做通信协议解析时,经常用unsigned char来存原始字节流。因为协议里的数据都是0~255,用unsigned char最合适,不会出现负数这种奇怪的值。

1.4 变量定义与初始化——好习惯从第一天养成

变量定义很简单:

int count;
float temperature;
char key;

但我要强调一个原则:变量一定要初始化。C语言不会自动帮你清零局部变量,它的初始值是随机的(栈上的垃圾数据)。

我的习惯:定义变量的同时就初始化,哪怕只是赋个0。这能避免90%的"莫名其妙"的bug。

int count = 0;
float temperature = 0.0f;
char key = '\0';

你想想看,如果一个变量没初始化就拿来用,程序的行为就是未定义的。未定义意味着什么?今天能跑,明天可能就崩了。我曾经接手过一个项目,里面有个变量没初始化,在调试版上跑得好好的,发布版就随机死机。查了三天才发现是这个问题。

1.5 常量——不变的值

C语言里定义常量有两种方式:

1.5.1 #define 宏定义

#define PI 3.14159
#define MAX_BUFFER_SIZE 1024

#define是预处理器指令,在编译前就把代码里的PI替换成3.14159。它不占内存,没有类型检查。

1.5.2 const 关键字

const double PI = 3.14159;
const int MAX_BUFFER_SIZE = 1024;

const是真正的常量,有类型,编译器会做类型检查。我个人更推荐用const,因为类型检查能帮你提前发现错误。

经验之谈:在嵌入式开发中,我习惯把硬件相关的常量用#define定义(比如引脚号、寄存器地址),把算法相关的常量用const定义。这样代码更清晰,也更容易维护。

1.6 sizeof运算符——测量数据大小

sizeof是C语言的一个运算符,不是函数。它用来计算变量或类型占用的字节数。

printf("int 的大小: %zu 字节\n", sizeof(int));
printf("float 的大小: %zu 字节\n", sizeof(float));
printf("double 的大小: %zu 字节\n", sizeof(double));
printf("char 的大小: %zu 字节\n", sizeof(char));

int arr[10];
printf("数组的大小: %zu 字节\n", sizeof(arr));     // 40字节(假设int是4字节)
printf("数组元素个数: %zu\n", sizeof(arr) / sizeof(arr[0]));  // 10

这里有个经典用法:用sizeof计算数组元素个数。这样写的好处是,就算你改了数组大小,代码也不用改。

注意:sizeof对指针求大小,得到的是指针本身的大小(4或8字节),不是它指向的数据的大小。这是新手最容易犯的错误之一。

我曾经在面试时问过一个候选人:sizeof("Hello")是多少?他回答5。实际上答案是6,因为字符串末尾还有个'\0'。你看,这种细节不注意,写出来的代码就会有隐患。

知识体系总览

下面这张图帮你理清本章的知识结构:

第1章:基本数据类型与变量 数据类型与变量 整型 int short / long / long long 浮点型 float/double 精度与范围 字符型 char signed / unsigned 变量定义与初始化 定义即初始化 常量 const / #define 类型安全 vs 宏替换 sizeof 运算符 计算字节数 核心原则:选对类型,初始化变量,注意精度与范围

这张图把本章内容分成了五大块:整型、浮点型、字符型、变量与常量、sizeof。每一块都有它的应用场景和注意事项。你学完这一章,应该能回答这几个问题:

  • 我的数据需要多大范围?该用哪种类型?
  • 变量要不要初始化?不初始化会怎样?
  • 用#define还是用const?什么时候用哪个?
  • sizeof能帮我做什么?

好了,这一章的内容就到这里。记住我反复强调的那句话:选对类型,初始化变量,注意精度与范围。这三个习惯养成了,你写出来的C代码就会稳很多。


公众号:蓝海资料掘金营,微信deep3321