抖音 C++ 已挂
1. #include头文件重复包含问题
在C/C++中,如果一个头文件被多次包含,会导致重复定义错误,例如结构体、变量或函数声明重复。为了解决这个问题,通常有两种方式:
方式一:#ifdef/#ifndef/#define/#endif
预处理器指令(传统做法)**
方式二:#pragma once
(现代做法,非标准但广泛支持)
两者原理类似,都是为了确保头文件只被编译一次,但#pragma once
更简洁、易读,编译器优化也更好,推荐在项目中统一使用。
重复包含问题不仅仅是语法错误问题,更可能引发链接错误和代码维护困难,因此良好的头文件保护宏是编写健壮C/C++代码的重要基础。
2. 详细解释栈帧
栈帧(Stack Frame) 是函数调用过程中,在栈上为每个函数单独分配的一块空间。它用于保存函数的局部变量、函数参数、返回地址、保存的寄存器等。函数调用遵循“先进后出”原则,栈帧也呈现出“压栈-弹栈”的特性。
3. 用户态到内核态穿越步骤
用户态与内核态是操作系统中权限级别(Ring 3 vs Ring 0)的划分,用户程序不能直接访问内核资源,必须通过“系统调用”、“中断与异常”实现。
典型穿越路径(以Linux x86_64为例)
- 用户程序发起系统调用
- CPU切换到内核态
- 跳转到内核中的 syscall 处理函数
- 内核执行系统服务
- 返回用户态
小结
系统调用实现了用户程序与内核的“安全桥梁”,深入理解穿越过程对于掌握系统调试、内核开发、以及安全防护(如系统调用过滤)至关重要。
4. 操作系统整体架构:六个执行体组件
现代操作系统的核心功能模块可以划分为六个主要组件(执行体):
1. 进程管理(Process Manager)
- 创建/销毁进程
- 分配PID
- 上下文切换、调度算法(如CFS)
2. 内存管理(Memory Manager)
- 虚拟内存分页机制
- 地址空间映射、段式管理
- 页表、TLB、交换空间管理(Swap)
3. I/O 管理器(I/O Manager)
- 驱动模型,设备抽象(统一接口)
- 异步/同步I/O
- 缓存系统、设备中断处理
4. 文件系统(File System)
- 文件目录结构
- 文件读写、权限控制
- 支持多种文件系统(NTFS, ext4 等)
5. 网络栈(Networking Stack)
- 套接字API(socket)
- 协议栈实现(TCP/IP)
- 多路复用机制(select/poll/epoll)
6. 安全与访问控制(Security & Access Control)
- 用户权限/组/ACL机制
- SELinux、AppArmor等增强机制
- 系统调用过滤(如seccomp)
5. 进程地址空间
操作系统为每个进程提供独立的虚拟地址空间,以实现内存隔离和安全性。一个典型的进程地址空间包括以下几个区域(以Linux x86_64为例):
Text段(代码段) | 存放程序可执行指令,只读,可共享 |
Data段 | 已初始化的全局/静态变量 |
BSS段 | 未初始化的全局/静态变量,初始化为0 |
Heap堆 | 动态分配内存(如malloc/new),由brk/sbrk或mmap实现 |
Stack栈 | 局部变量、函数调用栈帧,向低地址增长 |
mmap 区域 | 共享库、内存映射文件、线程栈等 |
内核空间(高地址) | 用户态不可访问,防止越权,系统调用时切换 |
进程地址空间通过MMU(内存管理单元)和页表机制映射到物理内存。每个进程都在自己的“虚拟世界”中运行,这种设计为多任务系统提供了安全与隔离的基础。
#面试问题记录#