目录

1. 嵌入式系统的核心特征

1.1 嵌入式 C 语言的特殊性

1.2 嵌入式 C 的核心应用场景

2. 嵌入式 C 开发环境搭建

2.1 核心开发工具链

3. C语言的关键字

4. C语言的运算符

5. C语言的数据类型

6. 变量

7. 常量

8. 数组


1. 嵌入式系统的核心特征

嵌入式系统是 “嵌入到对象体系中的专用计算机系统”,与通用计算机相比具有显著差异:

  • 资源受限:CPU 性能较弱(8 位 / 16 位 MCU 为主流)、内存容量小(KB 级 RAM/ROM)、存储有限(多无硬盘,依赖 Flash)
  • 硬件相关性强:直接操作硬件寄存器,程序需适配特定芯片(如 STM32、51 单片机、ESP32)
  • 实时性要求:多数需响应外部事件(如传感器信号、按键触发),部分场景需硬实时(如工业控制)
  • 低功耗需求:多采用电池供电(如物联网节点),需优化功耗延长续航
  • 稳定性优先:多为长期运行系统(如汽车 ECU),需避免崩溃与内存泄漏

1.1 嵌入式 C 语言的特殊性

嵌入式 C 语言以标准 C 为基础,扩展了硬件操作能力,同时存在严格约束:

特性维度

标准 C 语言

嵌入式 C 语言

编程目标

逻辑实现、跨平台

硬件控制、资源优化、实时响应

操作对象

软件数据结构

寄存器、IO 口、外设(UART/SPI)

内存管理

依赖 OS 内存分配

直接操作物理内存,慎用动态分配

执行环境

通用操作系统(Windows/Linux)

无 OS 或实时操作系统(RTOS)

调试方式

软件调试器(GDB)

硬件仿真器(J-Link)+ 在线调试

1.2 嵌入式 C 的核心应用场景

  • 工业控制:PLC(可编程逻辑控制器)、电机驱动、传感器数据采集
  • 物联网终端:智能门锁、环境监测节点、无线传感器网络
  • 消费电子:家电控制器、智能穿戴设备(手环、手表)
  • 汽车电子:车载 ECU(发动机控制单元)、车身控制器

2. 嵌入式 C 开发环境搭建

2.1 核心开发工具链

嵌入式开发需 “编译器 + IDE + 仿真器” 三位一体的工具链,以主流 ARM Cortex-M 系列 MCU 为例:

1. 交叉编译器

  • ARM GCC:开源交叉编译器,支持 ARM 架构 MCU,编译输出二进制文件(.bin/.hex)
  • Keil MDK:ARM 官方 IDE 集成编译器,支持 STM32 等主流 MCU,自带器件库
  • IAR Embedded Workbench:高优化编译器,适合对代码体积 / 速度要求高的场景

2.集成开发环境(IDE)

IDE 名称

适配架构

核心优势

适用场景

Keil MDK

ARM Cortex-M

器件库丰富,调试直观

STM32 开发、入门学习

VS Code + PlatformIO

跨架构(ARM/51/RISC-V)

插件生态强,支持多平台

多芯片项目、自定义开发

MPLAB X

PIC 系列 MCU

微芯官方支持,调试稳定

PIC 单片机开发

3. 硬件调试工具

  • 仿真器:J-Link(支持 ARM)、ST-Link(STM32 专用),实现在线调试、程序下载
  • 开发板:STM32F103C8T6(最小系统板)、51 单片机开发板,用于硬件验证
  • 辅助工具:示波器(测信号波形)、逻辑分析仪(抓总线数据)、万用表(测电压 / 电流)

3. C语言的关键字

  • C 语言标准共定义 32 个关键字.特别注意:关键字不能作为标识符(变量名、函数名等)使用

关键字

作用说明

auto

声明自动变量

break

跳出当前循环或 switch 语句

case

用于 switch 语句中,指定分支条件

char

声明字符型变量或函数返回值类型

const

声明只读变量(常量),其值不能被修改

continue

结束本次循环,直接进入下一次循环

default

用于 switch 语句中,指定默认分支(当所有 case 不匹配时执行)

do

与 while 配合使用,构成 do-while 循环结构

double

声明双精度浮点型变量或函数返回值类型

else

与 if 配合使用,指定 if 条件不成立时执行的分支

enum

声明枚举类型

extern

声明外部变量或函数(表示该变量 / 函数在其他文件中定义)

float

声明单精度浮点型变量或函数返回值类型

for

用于构成 for 循环结构

goto

无条件跳转语句,跳转到指定标签位置(不推荐频繁使用)

if

条件判断语句,指定条件成立时执行的分支

int

声明整型变量或函数返回值类型

long

用于声明长整型(如 long int)或长双精度型(long double)

register

声明寄存器变量(建议编译器将变量存储在寄存器中,以提高访问速度)

return

用于函数中,返回函数值并结束函数执行

short

修饰符,用于声明短整型(如 short int)

signed

声明有符号类型(可表示正数、负数和 0)

sizeof

计算变量或数据类型所占的字节数

static

 static静态变量声明符

struct

声明结构体类型

switch

多分支条件语句,根据表达式的值跳转到对应的 case 分支

typedef

为已有数据类型定义新的别名

union

声明共用体(联合体)类型,所有成员共享同一块内存空间

unsigned

修饰符,声明无符号类型(仅表示非负数)

void

1. 声明函数无返回值;2. 声明无类型指针;3. 表示空参数列表

volatile

提示编译器变量的值可能被意外修改,防止编译器过度优化(每次都从内存读取)

while

用于构成 while 循环或 do-while 循环结构

4. C语言的运算符

C 语言运算符是用于执行算术运算、逻辑判断、位操作等操作的符号,是连接数据与关键字的 “语法桥梁”。

C 语言运算符按功能可分为 8 大类

类别

运算符

功能说明

示例

算数运算符

+

加法

5 + 3

-

减法

5 - 3

*

乘法

5 * 3

/

除法(整数除法取商)

5 / 3

%

取余(仅用于整数)

5 % 3

++

自增(前 ++:先增后用;后 ++:先用后增)

int a=3; b=++a;

--

自减(前 --:先减后用;后 --:先用后减)

int a=3; b=a--;

赋值运算符

=

简单赋值

int a = 5;

+=

加后赋值(a += b 等价于 a = a + b)

a=5; a += 3;

-=

减后赋值

a=5; a -= 3;

*=

乘后赋值

a=5; a *= 3;

/=

除后赋值

a=5; a /= 3;

%=

取余后赋值

a=5; a %= 3;

关系运算符

==

等于

5 == 3

!=

不等于

5 != 3

>

大于

5 > 3

<

小于

5 < 3

>=

大于等于

5 >= 5

<=

小于等于

5 <= 3

逻辑运算符

&&

逻辑与(短路求值:两边都为真才为真)

(5>3) && (2>1)

||

逻辑或(短路求值:至少一边为真则为真)

(5>3) || (2<1)

!

逻辑非(取反)

!(5>3)

位运算符

&

按位与(对应位都为 1 则为 1)

5 & 3(二进制 101 & 011)

|

按位或(对应位有 1 则为 1)

5 | 3(101 | 011)

^

按位异或(对应位不同则为 1)

5 ^ 3(101 ^ 011)

~

按位取反(0 变 1,1 变 0)

~5(~000...0101)

<<

左移(各二进制位左移,右边补 0)

5 << 1(101 << 1)

>>

右移(各二进制位右移,左边补符号位)

5 >> 1(101 >> 1)

条件运算符

?:

三目运算符(条件?表达式 1: 表达式 2,条件为真取表达式 1,否则取表达式 2)

(5>3) ? 10 : 20

指针运算符

&

取地址(获取变量的内存地址)

&a

*

指针解引用(获取指针指向的变量值)

*p

其他运算符

sizeof

计算变量或类型的字节数

sizeof(int)

,

逗号运算符(从左到右执行,返回最后一个表达式结果)

a=2, b=3, a+b

5. C语言的数据类型

类型类别

具体类型

说明

示例声明

基本类型

char

字符型,通常占 1 字节,可表示 ASCII 字符或小整数

char c = 'A';

short

短整型,通常占 2 字节,范围约为 - 32768~32767

short num = 100;

int

整型,通常占 4 字节,范围约为 - 2147483648~2147483647

int age = 25;

long

长整型,通常占 4 或 8 字节,范围比 int 更大

long population = 1000000L;

long long

双长整型,通常占 8 字节,范围约为 - 9e18~9e18

long long big = 123456789LL;

float

单精度浮点型,占 4 字节,精度约 6~7 位有效数字

float pi = 3.14f;

double

双精度浮点型,占 8 字节,精度约 15~17 位有效数字

double price = 99.99;

long double

长双精度浮点型,占 8 或 16 字节,精度更高

long double weight = 123.45L;

类型修饰符

signed

有符号类型(默认),可表示正数、负数和 0

signed int a = -5;

unsigned

无符号类型,仅表示非负数,范围更大

unsigned int b = 100;

构造类型

数组

相同类型元素的集合,连续存储

int arr[5] = {1,2,3,4,5};

struct

结构体,可包含不同类型的成员,自定义复合类型

struct Student { char name[20]; int age; };

union

共用体,所有成员共享同一块内存空间,大小为最大成员的大小

union Data { int i; float f; };

enum

枚举类型,定义命名的整数常量集合,提高代码可读性

enum Color { RED, GREEN, BLUE };

指针类型

指针

存储变量的内存地址,可指向任意数据类型

int *p; char *str;

空类型

void

表示无类型,用于声明无返回值的函数、无类型指针或空参数列表

6. 变量

C 语言中的变量是程序运行过程中用于存储和操作数据的基本单元,其核心作用是临时或持久化保存程序执行过程中产生的数据(如数值、字符、地址等),并通过变量名实现对这些数据的便捷访问和修改。变量根据类型(如整型、浮点型、字符型等)确定可存储的数据范围和操作方式,根据作用域(全局或局部)决定其可被访问的范围,使得程序能够动态处理不同数据、记录中间结果(如计算过程中的临时值)、接收用户输入或输出结果,从而实现复杂的逻辑运算和数据处理。简单来说,变量是程序与数据之间的 “桥梁”,没有变量,程序将无法灵活地存储和操作数据,也就无法实现动态的功能逻辑。

变量类型

声明格式

示例说明

示例代码

基本类型变量

类型名 变量名;

声明一个 int 类型变量 age(未初始化);声明 int 类型变量 score 并初始化为 90

int age;int score = 90;

类型名 变量 1, 变量 2, ...;

声明 3 个 float 类型变量 x(未初始化)、y(初始化为 3.14)、z(未初始化)

float x, y = 3.14f, z;

signed/unsigned + 类型名

声明有符号 char 变量 c(值为 - 5);声明无符号 int 变量 count(值为 100,只能表示非负数)

signed char c = -5;unsigned int count = 100;

数组变量

类型名 数组名 [长度];

声明可存储 5 个 int 的数组 nums(未初始化);声明 3 个 int 的数组 arr,初始值为 1、2、3

int nums[5];int arr[3] = {1, 2, 3};

类型名 数组名 [] = {元素};

声明字符数组 str,未指定长度,由 "hello" 自动确定长度为 6(含结束符 '\0')

char str[] = "hello";

指针变量

类型名 * 指针名;

声明 int 变量 a(值为 5);声明 int 指针 p,指向 a 的地址(p 存储 a 的内存位置)

int a = 5;int *p = &a;

void * 通用指针名;

声明通用指针 ptr,可指向任意类型(如后续可指向 int、char 等,需强制转换)

void *ptr;

结构体变量

struct 结构体名 变量名;

先定义 Student 结构体(含 name 和 age 成员),再声明该类型变量 stu

struct Student {char name[20];int age;};struct Student stu;

结构体定义时直接声明变量

定义 Point 结构体(含 x、y 坐标),同时声明变量 p1 和 p2,p2 初始化为 (3,4)

struct Point {int x;int y;} p1, p2 = {3, 4};

枚举变量

enum 枚举名 变量名;

定义 Week 枚举(含周一至周三),声明变量 today 并赋值为周二(TUE 对应数值 1)

enum Week { MON, TUE, WED };enum Week today = TUE;

枚举定义时直接声明变量

定义 Color 枚举(红、绿),同时声明变量 c 并赋值为绿色(GREEN 对应数值 1)

enum Color { RED, GREEN } c = GREEN;

共用体变量

union 共用体名 变量名;

定义 Data 共用体(含 int 和 float 成员,共享内存),声明该类型变量 d

union Data {int i;float f;};union Data d;

变量名称需遵循 C 语言标识符规则,嵌入式开发中需额外注重 “语义化、模块化”,提升代码可读性:

规则:由字母、数字、下划线组成,首字符不能为数字,不能与关键字重名;

规范:采用 “前缀 + 语义” 命名法,前缀标识模块 / 功能,语义说明变量用途:

禁忌:避免a、b等无意义名称,禁止与关键字重名(如int while = 0;编译报错)。

变量分全局变量和局部变量

特性

全局变量(GlobalVariable)

局部变量(LocalVariable)

定义位置

定义在所有函数外部(包括main函数之外)

定义在函数内部、函数的参数列表中,或复合语句(如if、for的{}块)内部

作用域

从定义位置开始,在整个程序文件中可见,其他文件可通过extern声明访问

仅在定义它的函数或复合语句内部可见,出了该范围则无法访问

生命周期

从程序启动时创建,直到程序结束时销毁

从进入定义它的函数 / 复合语句时创建,函数返回 / 复合语句执行完毕时销毁

默认值

未初始化时,默认值为 0(数值类型)或空字符(字符类型)

未初始化时,值为随机的垃圾值(不确定)

存贮区域

存储在静态存储区(全局数据区)

存储在栈区(函数调用时分配,

注意事项:

1、当全局变量与局部变量同名时,在局部变量的作用域内,局部变量会覆盖全局变量(优先访问局部变量)

2、全局变量会一直占用内存,过多使用可能导致内存浪费,且会降低代码的封装性和安全性(任何函数都可能修改它

3、局部变量仅在函数执行时存在,内存使用更高效,是程序中更常用的变量类型

4、函数的参数也属于局部变量,作用域和生命周期与函数内部定义的局部变量相同 

7. 常量

常量是程序运行过程中值不能改变的量,主要有两种定义方式:

  1.  宏定义(#define)
#define PI 3.14159  // 定义宏常量PI

#define MAX(a, b) (a > b ? a : b)  // 定义宏函数(带参数的宏)

int main() {

    float area = PI * 2 * 2;  // 使用宏常量

    int max_num = MAX(5, 8);  // 使用宏函数,结果为8

    printf("面积:%.2f\n", area);

    printf("最大值:%d\n", max_num);

    return 0;

}

注意:宏定义在预处理阶段进行文本替换,无类型检查,且末尾不要加逗号。

2. const 关键字

const int MAX_SIZE = 100;  // 定义const常量MAX_SIZE

int main() {

    MAX_SIZE = 200;  // 错误,const常量的值不能修改

    return 0;

}

对比宏定义与 const:const 常量有类型检查,更安全;宏定义可定义带参数的宏,灵活性更高。

8. 数组

C 语言中的数组是一组相同数据类型元素的集合,其核心作用是高效批量存储和管理同类型数据。它通过连续的内存空间存储元素,允许通过下标快速访问任意元素,结合循环可便捷实现批量处理(如遍历、统计、修改等);作为函数参数时能简化批量数据传递,避免多个独立变量的繁琐操作;同时,字符数组是 C 语言中存储和处理字符串的基础,也是构建矩阵等复杂数据结构的基石。数组的连续存储特性还能优化内存使用效率,提升程序运行性能,但需注意其长度固定(静态数组)和下标不可越界的特性。

在 C 语言中,数组是一组相同数据类型元素的集合,元素在内存中连续存储。以下是数组的定义方式、分类及示例

数组类型

定义格式

说明

示例代码

一维数组

数据类型 数组名 [元素个数];

最基本的数组形式,元素按线性排列

int scores [5]; // 定义可存储 5 个 int 的数组float weights [3] = {50.5, 60.2, 70.1}; // 定义并初始化

数据类型 数组名 [] = {元素 1, 元素 2, ...};

不指定长度,由初始化元素个数自动确定数组长度

char fruits [] = {"apple", "banana"}; // 长度为 2 的字符串数组

二维数组

数据类型 数组名 [行数][列数];

可理解为 "数组的数组",按行优先存储

int matrix [2][3]; // 2 行 3 列的二维 int 数组int table [2][2] = {{1,2}, {3,4}}; // 初始化

数据类型 数组名 [行数][] = {初始化列表};

列数必须指定,行数可省略(由初始化列表确定)

int arr [][3] = {{1,2,3}, {4,5,6}}; // 自动确定为 2 行 3 列

字符数组

char 数组名 [长度];

用于存储字符序列,可表示字符串(需以 '\0' 结尾)

char name [10] = "Alice"; // 字符串初始化,自动添加 '\0'char str [5] = {'H','i','\0'}; // 显式添加结束符

动态数组

数据类型 * 指针名;指针名 = malloc (长度 * sizeof (数据类型));

运行时动态分配内存,长度可动态指定(需包含 stdlib.h)

int nums;nums = (int) malloc (5 * sizeof (int)); // 动态分配 5 个 int 的空间

特别注意:

数组名:代表数组首元素的地址,是一个常量指针,不能被赋值(如arr = &x;是错误的)。

元素访问:通过下标[ ]访问,下标从 0 开始(如scores[0]是数组的第一个元素)。

初始化规则:

初始化元素少于数组长度时,剩余元素自动初始化为 0(全局数组)或随机值(局部数组)。

字符数组若用字符串常量初始化(如"hello"),会自动在末尾添加空字符'\0',计算长度时需预留该位置。

动态数组注意事项:

使用malloc分配的内存需用free(指针名)释放,避免内存泄漏。

动态数组长度可通过变量指定(如int n=5; int *arr = malloc(n*sizeof(int));),而静态数组长度必须是常量。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐