BSS 段 是程序内存布局中的一个关键部分。以下是它的详细解释:
1. 定义与全称
- 全称:Block Started by Symbol(源自古老的 IBM 704 汇编指令)
- 中文名:未初始化数据段
- 作用:存放程序中 未初始化的全局变量和静态变量 ★★★
2. 内存布局中的位置
典型的内存布局如下:
高地址
┌─────────────┐
│ 栈(stack) │ ← 向下生长
├─────────────┤
│ 堆(heap) │ ← 向上生长
├─────────────┤
│ BSS段 │ ← 未初始化数据
├─────────────┤
│ DATA段 │ ← 已初始化数据
├─────────────┤
│ TEXT段 │ ← 代码和常量
└─────────────┘
低地址3. BSS 段的特点
| 特性 | 说明 |
|---|---|
| 内容 | 全部初始化为 0(或 NULL) |
| 文件大小 | 不占用可执行文件的磁盘空间 |
| 内存分配 | 运行时由加载器/操作系统分配并清零 |
| 变量类型 | 未初始化的全局变量、静态变量 |
| 作用域 | 全局有效,程序启动时创建,结束时释放 |
4. 代码示例
C 语言示例
#include <stdio.h>
int global_uninit; // 在 BSS 段(未初始化全局变量)
int global_init = 10; // 在 DATA 段(已初始化全局变量)
static int static_uninit; // 在 BSS 段(未初始化静态变量)
int main() {
static int local_static_uninit; // 在 BSS 段
static int local_static_init = 20; // 在 DATA 段
int local_var; // 在栈(stack)上
printf("BSS 变量地址: %p\n", &global_uninit);
printf("DATA 变量地址: %p\n", &global_init);
printf("栈变量地址: %p\n", &local_var);
return 0;
}
编译后查看各段大小
# 编译程序
gcc -o test test.c
# 查看各段大小
size test
输出示例:
text data bss dec hex filename
1500 600 200 2300 8fc test- text:代码段大小
- data:已初始化数据段大小
- bss:未初始化数据段大小
5. 为什么需要 BSS 段?
(1)节省磁盘空间
// 没有 BSS 段的情况
int large_array[1000000]; // 如果放在 DATA 段,文件会大 4MB
// 有 BSS 段的情况
int large_array[1000000]; // 只在可执行文件中记录"需要 4MB 零空间"
(2)提高加载速度
- 操作系统只需分配一块内存并清零,而不是从文件中读取大量零值。
(3)保证确定性初始化
- 所有 BSS 变量保证初始为 0,避免使用未初始化的随机值。
6. 嵌入式系统中的特殊考虑
启动代码中的 BSS 清零
在嵌入式系统(无操作系统)中,需手动清零 BSS:
/* 启动代码片段 (startup.s 或 crt0.s) */
extern char _bss_start[]; // 链接脚本定义的符号
extern char _bss_end[];
void clear_bss(void) {
char *p = _bss_start;
while (p < _bss_end) {
*p++ = 0;
}
}
链接脚本示例
/* linker.ld */
SECTIONS {
.text : { *(.text*) } > ROM
.data : { *(.data*) } > RAM AT>ROM
.bss : {
_bss_start = .; /* BSS 起始地址 */
*(.bss*)
*(COMMON) /* 公共块(未初始化的全局变量) */
_bss_end = .; /* BSS 结束地址 */
} > RAM
}
7. 与其它数据段的对比
| 段名 | 存放内容 | 是否占用文件空间 | 初始值 |
|---|---|---|---|
| TEXT | 代码、常量 | ✅ 是 | 编译时确定 |
| DATA | 已初始化全局/静态变量 | ✅ 是 | 编译时确定 |
| BSS | 未初始化全局/静态变量 | ❌ 否 | 运行时清零 |
| RODATA | 只读数据 | ✅ 是 | 编译时确定 |
| HEAP | 动态分配内存 | ❌ 否 | 运行时确定 |
| STACK | 局部变量 | ❌ 否 | 运行时确定 |
8. 常见问题
Q1: 指针在 BSS 段中初始值是什么?
int *p; // 在 BSS 段,初始值为 NULL
char *str; // 初始值为 NULL
Q2: 结构体在 BSS 段中如何初始化?
struct Point {
int x;
int y;
};
struct Point p; // p.x = 0, p.y = 0
Q3: 数组在 BSS 段中如何初始化?
int arr[100]; // 所有元素为 0
char str[50]; // 所有字节为 0
Q4: 如何确认变量在 BSS 段?
int a; // 在 BSS 段
int b = 0; // 在 DATA 段!(有初始化式,即使为0)
// 验证:编译时加 -Wuninitialized 警告
9. 高级话题
BSS 段的优化
# GCC 编译选项
# -fno-common: 将未初始化的全局变量放到 BSS 而非 COMMON
CFLAGS += -fno-common
多个 BSS 段(某些架构)
// 某些架构支持 .bss、.bss.small、.bss.large
// 用于不同访问速度的内存区域
__attribute__((section(".bss.fast"))) int fast_var;
__attribute__((section(".bss.slow"))) int slow_var;
