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

【C语言】数据类型

在 C 语言(Keil C51)中,数据类型决定了一份数据要占用多少存储空间、可以表示多大的数,以及程序会怎样解释这份数据。

可以把变量想成一个个盒子:数据类型就是盒子的规格。盒子太小,数据可能装不下;盒子太大,又会浪费 51 单片机有限的存储空间。

一、常用整数类型

整数类型用来保存没有小数部分的数。它们是 51 单片机程序中最常用的数据类型。

类型

占用空间

取值范围

常见用途

bit

1 位

0~1

开关、真假状态

char / signed char

1 字节

-128~127

较小的正负整数、字符

unsigned char

1 字节

0~255

端口数据、小计数值

short / int / signed int

2 字节

-32768~32767

普通正负整数

unsigned short / unsigned int

2 字节

0~65535

计数、定时值、ADC 数据

long / signed long

4 字节

-2147483648~2147483647

较大的正负整数

unsigned long

4 字节

0~4294967295

较大的累计值、时间值

signed 和 unsigned

signed 表示“有符号”,可以保存负数;unsigned 表示“无符号”,不能保存负数,但同样大小的空间可以表示更大的正数。

整数类型示例
C语言
1char temperature = -10;
2unsigned char ledIndex = 7;
3
4int error = -200;
5unsigned int adcValue = 1023;
6
7long position = -100000L;
8unsigned long runTimeMs = 100000UL;

如果数据不可能为负数,通常可以使用无符号类型。例如 LED 编号、按键次数和 ADC 采样值,都适合使用无符号整数。

在 Keil C51 的默认设置下,char 按有符号类型处理。为了让代码含义更明确,涉及数值范围时建议直接写 signed charunsigned char

二、浮点类型

当数据带有小数部分时,可以使用浮点类型。

类型

占用空间

取值范围

有效精度

float

4 字节

约 ±1.175494×10⁻³⁸~±3.402823×10³⁸

约 7 位有效数字

double

4 字节

与 float 相同

与 float 相同

在 Keil C51 中,doublefloat 都是 4 字节,并不会像许多桌面编译器那样提供更高精度。因此在 C51 程序中写 double,通常也得不到比 float 更大的范围或更高的精度。

浮点类型示例
C语言
1float voltage = 3.3f;
2float temperature = 25.5f;
3double distance = 12.75; // 在 Keil C51 中仍占 4 字节

普通 51 单片机通常没有浮点运算硬件。浮点数虽然方便,但会增加程序体积并占用更多运算时间;能用整数完成的简单计算,优先使用整数。

三、Keil C51 特有的类型

bit:保存一个状态

bit 只保存 01,只占 1 位,适合记录开关状态、完成标志和真假结果。

bit 类型示例
C语言
1bit ledEnabled = 1;
2bit keyPressed = 0;
3
4if (ledEnabled)
5{
6 // 点亮 LED
7}

多个简单状态如果都使用 unsigned char,每个变量会占 1 字节;使用 bit 可以节省珍贵的内部 RAM。

sbit:给硬件中的某一位起名字

sbit 不是普通变量,它用来表示可位寻址对象中的某一位。最常见的用途,是给单片机某个引脚起一个容易理解的名字。

sbit 类型示例
C语言
1#include <REG52.H>
2
3sbit LED = P1^0;
4sbit KEY = P3^2;
5
6void main(void)
7{
8 LED = 0; // 操作 P1.0
9 if (KEY == 0) // 读取 P3.2
10 {
11 LED = 1;
12 }
13
14 while (1);
15}

这里的 P1P3 已经在芯片头文件中声明,P1^0 表示 P1 寄存器的第 0 位。

sfr 和 sfr16:表示特殊功能寄存器

sfr 用来声明 8 位特殊功能寄存器,sfr16 用来声明由两个连续 8 位寄存器组成的 16 位特殊功能寄存器。它们对应真实硬件,不是普通 RAM 变量。

  • sfr:占 1 字节,例如端口寄存器 P0、P1、P2、P3。
  • sfr16:占 2 字节,例如由 DPL 和 DPH 组成的 16 位数据指针 DPTR。
  • 实际编程时通常直接包含与芯片匹配的头文件,不要重复声明头文件中已经定义的寄存器。

四、void:表示“没有数据”

void 表示“没有具体的数据类型”。初学阶段最常见的用法,是说明函数没有返回值,或者函数不接收参数。

void 示例
C语言
1void LED_On(void)
2{
3 // 这个函数不接收参数,也不返回数据
4}

五、数据类型和存储区域不要混淆

Keil C51 中还经常看到 dataidataxdatacode。它们说明数据放在哪里,并不会改变整数本身的大小和取值范围。

类型与存储区域
C语言
1unsigned char data counter; // unsigned char 类型,放在内部直接寻址 RAM
2unsigned char xdata buffer[100]; // unsigned char 数组,放在外部数据空间
3unsigned char code table[] = // unsigned char 数组,放在程序存储空间
4{
5 1, 2, 3, 4
6};

例如上面的 counterbuffer 中每个元素仍然都是 1 字节、范围仍然是 0~255;区别只是存储位置不同。

六、怎样选择数据类型

  • 只有 0 和 1 两种状态:使用 bit。
  • 数值在 0~255:优先考虑 unsigned char。
  • 需要保存较小的负数:使用 signed char。
  • 数值可能超过 255,但不超过 65535:使用 unsigned int。
  • 需要保存普通正负整数:使用 int。
  • 数值可能超过 16 位整数范围:使用 long 或 unsigned long。
  • 确实需要小数:使用 float,并留意程序体积和运算速度。
  • 操作单个硬件引脚:使用芯片头文件中的 sfr,并通过 sbit 为对应位命名。

选择数据类型时,不要一味追求“越大越好”。只要范围足够,较小的类型通常更节省 RAM,也更适合资源有限的 51 单片机。

七、超出范围会发生什么

变量只能保存自身范围内的数据。如果运算结果超出范围,就会出现溢出,得到的结果可能与直觉不同。

无符号整数溢出
C语言
1unsigned char value = 255;
2
3value = value + 1; // 结果回到 0

因此,在选择类型之前,要先估算数据可能达到的最小值和最大值,并为后续运算留出足够范围。