嵌入式基础知识——关键字
目录
1软件编程部分
1.1 关键字
1.2 关键词详细说明
1.2.1 数据类型(char, int, float, double, long, short, signed, unsigned, void)
1. char
2. int
3. float
4. double
5. long
6. short
7. signed / unsigned
8. void
1.2.2 存储类别(auto, static, extern, register)
1. auto(自动变量)
2. static(静态变量)
3. extern(外部变量)
4. register(寄存器变量)
5总结对比表:
1.2.3流程控制(if, else, switch, case, default, break, continue, goto)
1if-else 族
2 switch-case 族
3 break & continue
4goto
5一句话记忆口诀
6易错真题
1.2.4循环结构(for, while, do)
1for 循环
2while 循环
3do-while 循环
4三循环对比一览表
5通用可写/可读性建议
6 3个经典笔试坑
7一句话选型口诀
1.2.5函数相关(return)
1基本语法
2返回值分类
3main 的特殊规则
4返回指针 / 结构体
5与未定义行为(UB)相关的致命坑
6性能八卦:返回值优化(RVO)
7一句话记忆
1.2.6构造类型(struct, union, enum)
1struct —— 聚合打包
2union —— 同一地址多视角
3enum —— 整数符号化
4三兄弟对比速查表
5笔试 / 面试 3 连坑
6代码模板:协议解析一条龙
7一句话记忆
1.2.7类型限定(const, volatile)
1const:只读限定符
2volatile:易变限定符
3const volatile 组合
4总结表
6常见误区
1.2.8类型定义(typedef)
1基本语法
2常见用法速览
3与 #define 的区别
4 C++ 的替代:using
5实战小例子
6注意事项
1.2.9大小计算(sizeof)
1基本语法
2核心规则一览
3数组 VS 指针:经典坑
4结构体对齐与填充
5表达式不求值特性
6与 strlen 的区别
7获取元素个数惯用宏
8 32/64 位跨平台示例
9易错点速记
1.2.10_Bool 布尔类型(true/false,需包含 使用 bool 宏)。
1关键角色一览
2最小示例
3与 C++ 的区别
4转换语义
5没有 的写法(不推荐)
6位段、数组、对齐
7与宏 BOOL 的冲突
8编译器开关
9快速记忆
1.2.11_Complex 复数类型(如 double _Complex)。
1类型体系速览
2最小完整示例
3关键字 VS 宏
4初始化与存储布局
5运算与转换
6获取分量与常用函数
7与 C++ 的 区别
8编译器细节
9陷阱与建议
1.2.14inline 内联函数,建议编译器将函数体直接插入调用处(减少函数调用开销)。
1基本写法(C99 版)
2仅 inline 不加 static 的陷阱
4与宏对比
4编译器行为与优化选项
5链接视角:external inline(高阶)
6与 C++ 的差异速览
7实战 checklist
一句话总结
1.2.14restrict 指针限定符,告诉编译器该指针是访问数据的唯一方式,可优化代码。
1基本语法
2作用域与规则
3经典错误示范(UB)
4与 const / volatile 混用
5实际收益场景
6编译器表现
7与 C++ 的关系
8库函数示例(C23 原型)
9使用 checklist
2 硬件工程师笔试面试相关文章链接(部分链接)
摘要:本文系统梳理了C语言关键字的分类与特性,涵盖数据类型、存储类别、流程控制、函数相关等核心语法元素。重点解析了C89/C90的32个关键字和C99新增的5个关键字(_Bool、_Complex、inline等),详细介绍了各关键字的作用范围、内存布局、使用限制及常见陷阱。文章特别强调了类型限定符const/volatile的语义差异,inline函数的优化原理,以及restrict指针的性能优势。同时对比了C与C++在关键字处理上的差异,提供了跨平台编程的实用建议和笔试面试中的典型错误示例,帮助开发者深入理解C语言底层机制并规避未定义行为风险。
1软件编程部分
1.1 关键字
概念:被编译器保留、具有固定含义、不能作为标识符(变量名、函数名等)使用的单词。它们构成了 C 语言的语法骨架,决定了程序的结构、数据类型、控制流程等。
关键特征总结:
A 不能重定义:关键字不能作为变量名、函数名等标识符。
例子:int float = 3; //错误:'float' 是关键字。
B 大小写敏感:所有关键字必须小写
例子:int 有效,Int 无效。
C 编译器扩展:部分编译器(如 GCC)可能扩展关键字(如 typeof、asm),但这些不属于标准 C。
D 保留字:C标准还保留了一些 未来可能使用的标识符(如以_开头后跟大写字母或第二个_的标识符,如_MyVar或__myVar,应避免使用)。
1.2 关键词详细说明
表1 C89/C90(ANSI C)的32个关键字
类别 | 关键字 |
数据类型 | char, int, float, double, long, short, signed, unsigned, void |
存储类别 | auto, static, extern, register |
流程控制 | if, else, switch, case, default, break, continue, goto |
循环结构 | for, while, do |
函数相关 | return |
构造类型 | struct, union, enum |
类型限定 | const, volatile |
类型定义 | typedef |
大小计算 | sizeof |
表2 C99 新增 5个关键字
关键字 | 作用说明 |
_Bool | 布尔类型(true/false,需包含 <stdbool.h> 使用 bool 宏)。 |
_Complex | 复数类型(如 double _Complex)。 |
_Imaginary | 虚数类型(如 float _Imaginary)。 |
inline | 内联函数,建议编译器将函数体直接插入调用处(减少函数调用开销)。 |
restrict | 指针限定符,告诉编译器该指针是访问数据的唯一方式,可优化代码。 |
1.2.1 数据类型(char, int, float, double, long, short, signed, unsigned, void)
一句记忆
char 一字节,short 半字,int 自然,long 更长,float 单精,double 双精,signed 有负,unsigned 无负,void 无类型。
速查表
关键字 | 大小 | printf 格式 | 典型范围 |
char | 1 B | %hhd/%hhu | -128..127 或 0..255 |
signed char | 1 B | %hhd | -128..127 |
unsigned char | 1 B | %hhu | 0..255 |
short | 2 B | %hd | -32,768..32,767 |
unsigned short | 2 B | %hu | 0..65,535 |
int | 4 B | %d | ‑2³¹..2³¹‑1 |
unsigned int | 4 B | %u | 0..2³²‑1 |
long | 8 B | %ld | ‑2⁶³..2⁶³‑1 |
unsigned long | 8 B | %lu | 0..2⁶⁴‑1 |
float | 4 B | %f/%e/%g | ~7 位十进制有效数字 |
double | 8 B | %lf/%le/%lg | ~15 位十进制有效数字 |
void | — | — | 无类型/通用指针 |
数据类型关键字——本质、内存大小、取值范围、常量写法、常见用法/陷阱梳理
1. char
本质:最小的整数类型,通常用来存放1 byte 的字符编码(ASCII/UTF-8 等)。
大小:1 Byte(8 bit),sizeof(char)==1由标准硬性保证。
范围:
默认是否带符号由编译器决定(GCC/Clang 在 x86 上默认signed)。
signed char:-128 ~ 127unsigned char`:0 ~ 255
常量:'A', '\n', '\x41', L'中'(宽字符前缀 L 用 wchar_t)。
注意:
不要假设char一定是signed或unsigned。
用作字节数组时,显式写成uint8_t(typedef unsigned char uint8_t)最稳妥。
2. int
本质:CPU 的“自然字长”整数;通常就是寄存器宽度(32 位机→4 Byte,64 位机仍常见 4 Byte)。
大小:≥2 Byte;实际等于sizeof(int)。
范围:-2^(n-1) ~ 2^(n-1)-1,n=16/32/64 位。
常量:42, 0x2a, 052(八进制),42u, 42l,42ul。
注意:
与指针宽度无关;64 位 Linux 上 int 仍是 4 字节。
整型提升:比int小的类型(char, short, 枚举)在表达式里会先变成int。
3. float
本质:单精度 IEEE-754 浮点。
大小:4 Byte。
精度:≈7 位十进制有效数字;指数范围 ≈ 10^±38。
常量:3.14f, 1e-3f(必须带 f 后缀,否则是double)。
注意:
与==比较不可靠,用fabs(a-b) < EPS。
默认浮点提升会把float提升成double。
4. double
本质:双精度 IEEE-754。
大小:8 Byte(大多数平台)。
精度:≈15~16 位十进制有效数字。
常量:3.1415,1.23e-4(无后缀默认就是 double)。
注意:
在 32 位 MCU 上运算慢,嵌入式常强制 -fsingle-precision-constant。
与 long double区别:后者可能 80/128 bit,但仍是 IEEE-754 扩展。
5. long
本质:扩展宽度的有符号整数。
大小:≥ int;32 位平台常 4 B,64 位 Linux/Unix 为 8 B(LLP64 的 Windows 仍是 4 B)。
范围:对应位数的有符号范围。
常量:100000L, 0xCAFEBABEL, 1000000UL。
注意:
与指针宽度无关;long 在 Windows x64 仍是 4 Byte,易踩坑。
要写跨平台文件偏移请用 off_t/int64_t 而不是 long。
6. short
本质:半字长整数。
大小:≥2 Byte;几乎所有平台都是 2 Byte。
范围:-32,768 ~ 32,767(signed)。
常量:(short)5(无专用后缀,需强制转换)。
注意:
节省内存或做网络报文结构体时常用。
整型提升后表达式里会变成 int 再运算,注意符号扩展。
7. signed / unsigned
本质:类型修饰符,不能单独使用,必须搭配整型(char, short, int, long)。
规则:
默认 int, long, short 为 signed。
char是否signed由实现决定。
组合顺序随意:unsigned long int ≡ unsigned long。
注意:
混合运算时遵循“整型提升→转换等级→符号性”三步曲。
unsigned与signed比较会先把signed 转换成 unsigned,易出负数大坑。
8. void
本质:“无类型”
三个用途:
1. 函数无返回值:int foo(void)
2. 函数无参数:现代 C 用 int bar(void)(int baz()在老标准里表示“未知参数”)。
3. 通用指针:void *p 可指向任意数据,但解引用前必须强制转换。
注意:
void变量或数组非法(void a; 编译错误)。
void与任意对象指针可隐式转换(C 语言独有),但 C++ 需static_cast。
1.2.2 存储类别(auto, static, extern, register)
C 语言中,存储类别(Storage Class)决定了变量的生命周期、作用域、以及内存存储位置。主要有四种存储类别说明符:auto、static、extern、register。
1. auto(自动变量)
作用域:局部作用域(代码块内)
生命周期:进入代码块时创建,退出时销毁
存储位置:栈(stack)
默认行为:局部变量默认就是 auto,通常省略不写
示例:void func() { auto int x = 10; // 等价于 int x = 10;}
2. static(静态变量)
作用域:
- 局部 static:只在函数内可见
- 全局 static:只在当前文件内可见(内部链接)
生命周期:整个程序运行期间
存储位置:静态存储区(data segment)
特点:只初始化一次,保留上次值
示例:void counter() { static int count = 0; count++; printf("%d\n", count); // 每次调用输出递增}
3. extern(外部变量)
作用域:全局作用域(跨文件)
生命周期:整个程序运行期间
存储位置:静态存储区
用途:声明一个在其他文件中定义的变量
示例:// file1.cint global = 42;// file2.cextern int global; // 使用 file1.c 中的 global
4. register(寄存器变量)
作用域:局部作用域
生命周期:同 auto
存储位置:建议存储在 CPU 寄存器中(只是建议,编译器可忽略)
限制:不能取地址(®_var 非法)
示例:void func() { register int i; for (i = 0; i < 1000; i++);}
5总结对比表:
存储类别 | 作用域 | 生命周期 | 存储位置 | 初始值 | 备注 |
auto | 局部 | 函数调用期间 | 栈 | 随机 | 默认省略 |
static | 局部/全局 | 整个程序运行期 | 静态区 | 0 | 只初始化一次,保留值 |
extern | 全局 | 整个程序运行期 | 静态区 | 0 | 跨文件引用 |
register | 局部 | 函数调用期间 | 寄存器(建议) | 随机 | 不能取地址,可能优化为普通变量 |
1.2.3流程控制(if, else, switch, case, default, break, continue, goto)
C 语言里,流程控制语句负责“程序该走哪条路”。下面把
if / else、switch / case / default、break / continue、goto
全部拆开讲:先给语法模板,再给“易错点”,最后给“一句话记忆”。
1if-else 族
语法:
if (表达式) 语句1:
if (表达式) 语句1;else 语句2;
if (表达式1) 语句1;else if (表达式2) 语句2;else 语句3;
关键规则
- 表达式只要 非 0 即为真。
- else 永远与离它最近且尚未配对的 if 结合(俗称“悬空 else”问题)。
- 单条语句可省 {},但永远加花括号是最省 bug 的做法。