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;