嵌入式学习15
标题:C语言底层核心|位运算详解 + 程序五大内存分区全梳理)
前言
最近系统学习C语言底层知识点,今天啃完两大重难点:位运算和程序内存分区管理。位运算是嵌入式、驱动开发必备技能,直接操作二进制比特位;内存分区是理解程序运行、排查内存泄漏、段错误的根本。本文整理完整知识点、实操模板、踩坑易错点,适合零基础巩固、面试复习。
一、位运算:直接操作二进制比特位
1. 六种基础位运算符
位运算仅支持整型数据(char/short/int/long),浮点数float、double无法参与运算。
| 运算符 | 运算规则 | 典型场景 |
|---|---|---|
| & 按位与 | 对应bit全1才为1,否则0 | 指定位清零、提取特定位 |
| | 按位或 | 对应bit有1则1,全0才0 | 将指定bit置1 |
| ^ 按位异或 | 对应bit相同为0,不同为1 | 翻转bit、交换两数无临时变量 |
| ~ 按位取反 | 所有bit 0↔1 | 配合与运算清零特定位 |
| << 左移 | 整体左移N位,低位补0 | 快速乘以2的N次方 |
| >> 右移 | 整体右移N位,有符号补符号位 | 快速除以2的N次方 |
2. 工业级常用位操作模板
(1)将数字第n位设置为1
// n为目标bit下标,从0开始计数num|=(1<<n);(2)将数字第n位清零
num&=~(1<<n);(3)异或交换两个整数(无需临时变量)
voidswap(int*a,int*b){*a=*a^*b;*b=*a^*b;*a=*a^*b;}3. 高频注意事项&易错坑
- 区分逻辑运算符与位运算符
&& ||是逻辑运算,结果只有0/1;& | ^是位运算,操作二进制每一位,完全不能混用。 - 移位运算优先级低于加减
1 + 3 << 1等价(1+3) << 1 = 8,不是1 + (3<<1)=7,复杂运算建议加括号。 - 有符号数右移补符号位
负数右移永远为负数,无符号数字右移统一补0;移位溢出会丢失数据,避免超大移位。 ~取反容易踩坑~1结果不是0,而是所有bit翻转的负数(计算机用补码存储负数),不能直接用~num判断正负。
二、 C程序内存分区管理(Linux环境)
1. 五大内存分区完整图解
程序运行时内存从低地址到高地址分为:文本段、数据区、栈区、堆区、CPU寄存器。
- .text 文本段(只读)
存放所有函数代码、程序指令,权限只读,修改会直接段错误,生命周期全程伴随程序。 - 数据区(编译阶段分配,程序结束释放)
- .data:已初始化全局变量、static静态变量;
- .bss:未初始化全局/static变量,程序加载时自动填充0;
- .rodata:字符串常量、const只读常量,禁止写操作。
- 栈区 stack(操作系统自动管理)
存放局部变量、函数形参、函数返回地址;进入函数分配,函数执行完毕自动回收。
坑:局部变量不初始化,值为随机脏数据;栈空间很小,禁止超大数组。 - 堆区 heap(程序员手动管理)
唯一自主控制生命周期的内存,通过malloc/calloc/realloc申请,free手动释放。- 忘记释放 → 内存泄漏,程序长时间运行内存占用持续上涨;
- 重复free、free栈变量/全局变量 → 程序崩溃。
- 寄存器 register
CPU高速存储单元,register修饰的变量优先存入寄存器,读写速度远超内存。
2. 堆区动态内存核心API
#include<stdlib.h>// 申请size字节堆内存,返回void*,未初始化void*malloc(size_tsize);// 申请count个size空间,自动初始化为0void*calloc(size_tcount,size_tsize);// 扩容/缩容已有堆内存void*realloc(void*ptr,size_tnew_size);// 释放堆内存voidfree(void*ptr);规范写法:free后手动置空,杜绝野指针
int*p=malloc(40);free(p);p=NULL;// 释放后置空,避免野指针3. 共用体union与大小端存储
- union特点:所有成员共享同一块内存,空间大小等于最大成员占用字节;
- 大小端模式:
- 小端(PC、ARM主流):低内存地址存放数据低位;
- 大端(网络协议):低内存地址存放数据高位;
可通过union快速判断当前设备存储模式。
4. 内存模块易错点汇总
- 函数绝对不能返回局部变量地址:局部变量存栈,函数结束栈销毁,指针变为野指针;
"hello"字符串常量存.rodata只读段,不能修改字符:char *s = "abc"; s[0]='x';直接崩溃;- static修饰局部变量,存储在数据区,仅第一次调用函数初始化;普通局部变量每次进函数重建;
- 栈空间有限,大容量数组、缓冲区统一放堆;
- 堆内存只能free一次,重复free、释放非malloc指针直接触发段错误;
- 数组越界读写会破坏相邻内存,产生无规律随机bug,极难调试。
三、今日学习总结
- 位运算偏向底层硬件开发,熟记置1、清零、异或交换三大模板,区分位运算与逻辑运算;
- 内存分区是C语言排错核心,分清栈/堆/数据区存放数据类型,牢记堆内存malloc/free配对使用;
- 高频踩坑:野指针、内存泄漏、栈溢出、修改只读字符串、返回局部变量地址;
- 拓展方向:后续结合指针、结构体、动态数组,实战堆内存管理,实现动态链表。
