在C语言中,内存通常分为几个不同的数据区,每个数据区有不同的用途。以下是C语言中的主要数据区:
- 代码区(Text Segment):
- 存储程序的机器代码,即编译后的指令。代码区通常是只读的,防止程序意外修改自己的指令。
- 示例作用:存储函数定义。
- 数据区(Data Segment):
- 又分为静态数据区(静态数据段)和BSS段。
- 静态数据区(.data segment):存储已初始化的全局变量和静态变量。
- BSS段(.bss segment):存储未初始化的全局变量和静态变量,系统在程序开始运行时将这些变量初始化为零。
- 堆区(Heap Segment):
- 用于动态分配内存,由程序在运行时显式地分配和释放(如使用malloc、free)。
- 示例作用:存储动态分配的对象。
- 栈区(Stack Segment):
- 用于存储局部变量、函数参数、返回地址等。栈区由系统自动分配和释放,通常用于函数调用。
- 示例作用:存储函数的局部变量和参数。
以下是一个示例代码展示了这些数据区的作用:
#include <stdio.h>
#include <stdlib.h>
// 全局变量 - BSS段(未初始化)
int global_uninit_var;
// 全局变量 - 数据段(已初始化)
int global_init_var = 100;
// 静态变量 - 数据段(已初始化)
static int static_init_var = 200;
// 函数定义 - 代码区
void function() {
// 局部变量 - 栈区
int local_var = 10;
printf("Local variable: %d\n", local_var);
// 动态分配的内存 - 堆区
int *heap_var = (int *)malloc(sizeof(int));
*heap_var = 20;
printf("Heap variable: %d\n", *heap_var);
// 释放动态分配的内存
free(heap_var);
}
int main() {
// 打印全局变量和静态变量
printf("Global uninitialized variable: %d\n", global_uninit_var);
printf("Global initialized variable: %d\n", global_init_var);
printf("Static initialized variable: %d\n", static_init_var);
// 调用函数
function();
return 0;
}
在这段代码中:
global_uninit_var
是一个未初始化的全局变量,存储在BSS段。global_init_var
是一个已初始化的全局变量,存储在数据段。static_init_var
是一个已初始化的静态变量,存储在数据段。function
是一个函数定义,存储在代码区。local_var
是一个局部变量,存储在栈区。heap_var
是一个动态分配的内存块,存储在堆区。
通过这个示例,可以清晰地看到C语言程序中各个数据区的使用和作用。
nm
命令可以列出目标文件(如可执行文件、库文件等)中的符号,并显示每个符号所在的段和其他信息。使用nm
命令可以帮助我们查看C语言程序中的不同数据区。以下是一个具体的例子,演示如何通过nm
命令查看各个数据区。
示例代码
#include <stdio.h>
#include <stdlib.h>
// 全局变量 - BSS段(未初始化)
int global_uninit_var;
// 全局变量 - 数据段(已初始化)
int global_init_var = 100;
// 静态变量 - 数据段(已初始化)
static int static_init_var = 200;
// 函数定义 - 代码区
void function() {
// 局部变量 - 栈区
int local_var = 10;
printf("Local variable: %d\n", local_var);
// 动态分配的内存 - 堆区
int *heap_var = (int *)malloc(sizeof(int));
*heap_var = 20;
printf("Heap variable: %d\n", *heap_var);
// 释放动态分配的内存
free(heap_var);
}
int main() {
// 打印全局变量和静态变量
printf("Global uninitialized variable: %d\n", global_uninit_var);
printf("Global initialized variable: %d\n", global_init_var);
printf("Static initialized variable: %d\n", static_init_var);
// 调用函数
function();
return 0;
}
编译并使用nm命令
- 编译代码:
gcc -o example example.c
- 使用nm命令:
nm example
nm命令输出示例
0000000000401050 B global_uninit_var
0000000000401060 D global_init_var
0000000000401064 b static_init_var
0000000000401040 T function
0000000000401080 T main
解释nm命令的输出
- BSS段:
- 符号:
global_uninit_var
- 类型:
B
- 地址:
0000000000401050
- 描述:未初始化的全局变量存储在BSS段,符号类型为
B
。
- 数据段:
- 符号:
global_init_var
- 类型:
D
- 地址:
0000000000401060
- 描述:已初始化的全局变量存储在数据段,符号类型为
D
。 - 符号:
static_init_var
- 类型:
b
- 地址:
0000000000401064
- 描述:已初始化的静态变量存储在数据段,符号类型为
b
。
- 代码段(文本段):
- 符号:
function
- 类型:
T
- 地址:
0000000000401040
- 描述:函数定义存储在代码段,符号类型为
T
。 - 符号:
main
- 类型:
T
- 地址:
0000000000401080
- 描述:main函数存储在代码段,符号类型为
T
。
总结
通过nm
命令,我们可以看到每个符号的类型和地址,从而了解它们位于哪一个数据区。不同符号类型表示不同的数据区:
B
或b
:BSS段D
或d
:数据段T
或t
:代码段(文本段)
局部变量和动态分配的内存不会出现在nm
命令的输出中,因为它们在运行时分配,不是符号表的一部分。