底层知识

内容简介

底层知识用于解释程序如何从源码变成可执行文件,以及变量、函数、动态内存在运行时分别放在哪里。理解这些内容后,指针、生命周期、内存泄漏和悬挂指针会更容易理解。

用法

编译流程

源代码
  -> 预处理
  -> 编译
  -> 汇编
  -> 链接
  -> 可执行文件

常见含义:

  • 预处理:处理 #include、宏、条件编译。
  • 编译:把 C/C++ 代码转换成汇编或中间表示。
  • 汇编:生成目标文件。
  • 链接:把多个目标文件和库合成可执行文件。

常见内存区域

区域主要内容生命周期
代码区程序指令程序运行期间
全局/静态区全局变量、静态变量程序运行期间
常量区字符串字面量、部分常量程序运行期间
栈区局部变量、函数参数、返回地址随函数调用创建和销毁
堆区malloc/new 申请的内存手动释放或由对象管理
int global_value = 1;
 
int main()
{
    int local_value = 2;
    static int static_value = 3;
    int *heap_value = new int(4);
 
    delete heap_value;
    heap_value = nullptr;
    return 0;
}

最佳代码实践

  • 不要返回局部变量的地址或引用。
  • C++ 中优先用 RAII 管理堆资源,例如 std::vectorstd::string、智能指针。
  • newdelete 配对,mallocfree 配对,不要混用。
  • 动态内存释放后把裸指针置空,减少误用概率。

错误用法

int* bad()
{
    int value = 10;
    return &value;  // 错误:value 在函数返回后已经销毁
}
int *p = new int(10);
free(p);  // 错误:new 申请的内存必须 delete
int *p = malloc(sizeof(int));
*p = 10;
// 错误:忘记 free(p),产生内存泄漏

注意事项

  • “栈快、堆灵活”只是粗略说法,实际还要看对象大小、生命周期和所有权设计。
  • 字符串字面量通常不可修改,不要用 char* p = "hello"; p[0] = 'H';
  • 内存地址的具体数值每次运行可能不同,不要依赖打印出来的地址。

相关:CandCpp指针CandCpp预处理RAII智能指针

学习路径