四、文件系统与IO高级操作
4.1 文件随机访问与内存映射
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
/**
* 文件随机访问
*/
void random_file_access() {
FILE *fp = fopen("data.bin", "wb+");
if (!fp) return;
// 写入固定大小的记录
typedef struct {
int id;
char name[32];
float score;
} Record;
Record records[] = {
{1, "张三", 85.5},
{2, "李四", 92.0},
{3, "王五", 78.5},
{4, "赵六", 88.0}
};
fwrite(records, sizeof(Record), 4, fp);
// 随机访问:直接定位到第3条记录(索引2)
fseek(fp, 2 * sizeof(Record), SEEK_SET);
Record r;
fread(&r, sizeof(Record), 1, fp);
printf("第3条记录:id=%d, name=%s, score=%.1f\n", r.id, r.name, r.score);
// 修改第2条记录
Record newRecord = {2, "李四_updated", 95.0};
fseek(fp, 1 * sizeof(Record), SEEK_SET);
fwrite(&newRecord, sizeof(Record), 1, fp);
fclose(fp);
}
/**
* 内存映射文件(mmap)
* 将文件映射到内存,像访问内存一样访问文件
*/
void mmap_file_demo() {
const char *filename = "mmap_test.txt";
const char *content = "Hello, Memory Mapped File!\n";
// 写入文件
int fd = open(filename, O_RDWR | O_CREAT, 0644);
if (fd == -1) {
perror("open");
return;
}
size_t len = strlen(content);
if (ftruncate(fd, len) == -1) {
perror("ftruncate");
close(fd);
return;
}
// 内存映射
char *mapped = (char*)mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (mapped == MAP_FAILED) {
perror("mmap");
close(fd);
return;
}
// 直接通过内存写入
memcpy(mapped, content, len);
// 同步到磁盘
msync(mapped, len, MS_SYNC);
printf("写入成功,映射地址:%p\n", mapped);
printf("读取内容:%s", mapped);
// 修改内存映射的内容
mapped[0] = 'h';
printf("修改后:%s", mapped);
// 解除映射
munmap(mapped, len);
close(fd);
}
/**
* 文件锁(防止多进程同时写入)
*/
#include <fcntl.h>
void file_lock_demo() {
int fd = open("shared.dat", O_RDWR | O_CREAT, 0644);
if (fd == -1) {
perror("open");
return;
}
struct flock lock;
lock.l_type = F_WRLCK; // 写锁
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0; // 锁定整个文件
lock.l_pid = getpid();
// 尝试获取锁
if (fcntl(fd, F_SETLK, &lock) == -1) {
perror("fcntl");
printf("文件已被其他进程锁定\n");
close(fd);
return;
}
printf("获取文件锁成功,PID:%d\n", getpid());
// 执行文件操作
sleep(5);
// 释放锁
lock.l_type = F_UNLCK;
fcntl(fd, F_SETLK, &lock);
printf("释放文件锁\n");
close(fd);
}
4.2 目录操作与文件遍历
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
/**
* 递归遍历目录
*/
void list_directory(const char *path, int depth) {
DIR *dir = opendir(path);
if (!dir) {
perror("opendir");
return;
}
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
// 跳过当前目录和上级目录
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
// 构建完整路径
char full_path[1024];
snprintf(full_path, sizeof(full_path), "%s/%s", path, entry->d_name);
// 获取文件信息
struct stat st;
if (stat(full_path, &st) == -1) {
perror("stat");
continue;
}
// 打印缩进
for (int i = 0; i < depth; i++) {
printf(" ");
}
// 判断文件类型
if (S_ISDIR(st.st_mode)) {
printf("[目录] %s\n", entry->d_name);
// 递归遍历子目录
list_directory(full_path, depth + 1);
} else {
printf("[文件] %s (%ld 字节)\n", entry->d_name, st.st_size);
}
}
closedir(dir);
}
/**
* 获取文件详细信息
*/
void file_info(const char *filename) {
struct stat st;
if (stat(filename, &st) == -1) {
perror("stat");
return;
}
printf("文件:%s\n", filename);
printf("大小:%ld 字节\n", st.st_size);
printf("权限:%o\n", st.st_mode & 0777);
printf("所有者UID:%d\n", st.st_uid);
printf("组GID:%d\n", st.st_gid);
printf("最后访问时间:%ld\n", st.st_atime);
printf("最后修改时间:%ld\n", st.st_mtime);
printf("最后状态改变时间:%ld\n", st.st_ctime);
// 判断文件类型
printf("类型:");
if (S_ISREG(st.st_mode)) printf("普通文件\n");
else if (S_ISDIR(st.st_mode)) printf("目录\n");
else if (S_ISLNK(st.st_mode)) printf("符号链接\n");
else if (S_ISCHR(st.st_mode)) printf("字符设备\n");
else if (S_ISBLK(st.st_mode)) printf("块设备\n");
else if (S_ISFIFO(st.st_mode)) printf("管道\n");
else if (S_ISSOCK(st.st_mode)) printf("套接字\n");
else printf("未知\n");
}
/**
* 复制文件
*/
int copy_file(const char *src, const char *dst) {
FILE *src_fp = fopen(src, "rb");
if (!src_fp) {
perror("fopen src");
return -1;
}
FILE *dst_fp = fopen(dst, "wb");
if (!dst_fp) {
perror("fopen dst");
fclose(src_fp);
return -1;
}
char buffer[8192];
size_t bytes;
while ((bytes = fread(buffer, 1, sizeof(buffer), src_fp)) > 0) {
fwrite(buffer, 1, bytes, dst_fp);
}
fclose(src_fp);
fclose(dst_fp);
return 0;
}
void directory_demo() {
printf("当前目录内容:\n");
list_directory(".", 0);
printf("\n文件信息:\n");
file_info("test.txt");
}
五、预处理与编译链接
5.1 预处理高级技巧
/**
* 高级预处理技巧
*/
// 1. 可变参数宏(C99)
#define DEBUG_PRINT(fmt, ...) \
printf("[DEBUG] %s:%d: " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
// 2. 字符串化和连接
#define STRINGIFY(x) #x
#define CONCAT(a, b) a##b
// 3. 条件编译与多平台支持
#if defined(_WIN32) || defined(_WIN64)
#define PLATFORM "Windows"
#define PATH_SEPARATOR '\\'
#elif defined(__linux__)
#define PLATFORM "Linux"
#define PATH_SEPARATOR '/'
#elif defined(__APPLE__)
#define PLATFORM "MacOS"
#define PATH_SEPARATOR '/'
#else
#define PLATFORM "Unknown"
#endif
// 4. 断言宏
#ifdef DEBUG
#define ASSERT(expr) \
do { \
if (!(expr)) { \
fprintf(stderr, "Assertion failed: %s at %s:%d\n", \
#expr, __FILE__, __LINE__); \
abort(); \
} \
} while (0)
#else
#define ASSERT(expr) ((void)0)
#endif
// 5. 防止头文件重复包含
#ifndef MY_HEADER_H
#define MY_HEADER_H
// 头文件内容
#endif
// 6. 编译时检查(静态断言)
#define STATIC_ASSERT(expr, msg) \
typedef char static_assert_##msg[(expr) ? 1 : -1]
STATIC_ASSERT(sizeof(int) == 4, int_size_not_4);
void preprocessor_demo() {
DEBUG_PRINT("程序启动");
DEBUG_PRINT("变量值:%d", 100);
printf("平台:%s\n", PLATFORM);
int x = 5;
ASSERT(x > 0);
printf("STRINGIFY(hello) = %s\n", STRINGIFY(hello));
int CONCAT(var, 123) = 42;
printf("var123 = %d\n", var123);
}
5.2 多文件项目组织
/**
* 多文件项目组织
*
* 项目结构:
* project/
* ├── include/
* │ ├── utils.h // 公共函数声明
* │ ├── list.h // 数据结构声明
* │ └── config.h // 配置宏
* ├── src/
* │ ├── main.c // 主程序
* │ ├── utils.c // 工具函数实现
* │ └── list.c // 数据结构实现
* └── Makefile // 编译脚本
*/
// utils.h
#ifndef UTILS_H
#define UTILS_H
// 外部函数声明
void print_message(const char *msg);
int max(int a, int b);
int min(int a, int b);
// 内联函数(定义在头文件)
static inline int square(int x) {
return x * x;
}
#endif
// utils.c
#include "utils.h"
#include <stdio.h>
void print_message(const char *msg) {
printf("%s\n", msg);
}
int max(int a, int b) {
return a > b ? a : b;
}
int min(int a, int b) {
return a < b ? a : b;
}
// main.c
#include <stdio.h>
#include "utils.h"
#include "list.h"
int main() {
print_message("Hello, Multi-file Project!");
printf("square(5) = %d\n", square(5));
printf("max(10, 20) = %d\n", max(10, 20));
// 使用链表
LinkedList list;
linkedlist_init(&list);
linkedlist_push_back(&list, 100);
linkedlist_print(&list);
linkedlist_free(&list);
return 0;
}
// Makefile
/*
CC = gcc
CFLAGS = -Wall -Wextra -O2 -Iinclude
SRCDIR = src
OBJDIR = obj
BINDIR = bin
SOURCES = $(wildcard $(SRCDIR)/*.c)
OBJECTS = $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
TARGET = $(BINDIR)/app
$(TARGET): $(OBJECTS)
mkdir -p $(BINDIR)
$(CC) $^ -o $@
$(OBJDIR)/%.o: $(SRCDIR)/%.c
mkdir -p $(OBJDIR)
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -rf $(OBJDIR) $(BINDIR)
.PHONY: clean
*/
六、系统调用与底层编程
6.1 进程控制
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
/**
* 进程创建与控制
*/
void process_control() {
pid_t pid = fork();
if (pid < 0) {
perror("fork");
exit(1);
} else if (pid == 0) {
// 子进程
printf("子进程:PID=%d, 父进程PID=%d\n", getpid(), getppid());
sleep(2);
printf("子进程结束\n");
exit(0);
} else {
// 父进程
printf("父进程:PID=%d, 子进程PID=%d\n", getpid(), pid);
// 等待子进程结束
int status;
pid_t child_pid = wait(&status);
if (WIFEXITED(status)) {
printf("子进程 %d 正常退出,退出码:%d\n", child_pid, WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("子进程被信号 %d 终止\n", WTERMSIG(status));
}
}
}
/**
* 进程替换(exec族函数)
*/
void process_exec() {
pid_t pid = fork();
if (pid == 0) {
// 子进程执行ls命令
execlp("ls", "ls", "-l", "-a", NULL);
// 如果exec执行失败
perror("execlp");
exit(1);
} else {
wait(NULL);
printf("ls命令执行完成\n");
}
}
/**
* 信号处理
*/
void signal_handler(int signum) {
printf("捕获到信号:%d\n", signum);
if (signum == SIGINT) {
printf("收到SIGINT,程序即将退出\n");
exit(0);
}
}
void signal_demo() {
// 注册信号处理函数
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
printf("进程PID:%d\n", getpid());
printf("按Ctrl+C发送SIGINT信号\n");
while (1) {
sleep(1);
printf("运行中...\n");
}
}
6.2 管道与进程间通信
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
/**
* 管道(Pipe)通信
*/
void pipe_demo() {
int pipefd[2];
char buffer[256];
if (pipe(pipefd) == -1) {
perror("pipe");
exit(1);
}
pid_t pid = fork();
if (pid == 0) {
// 子进程:写入管道
close(pipefd[0]); // 关闭读端
const char *msg = "Hello from child process!";
write(pipefd[1], msg, strlen(msg) + 1);
close(pipefd[1]);
exit(0);
} else {
// 父进程:读取管道
close(pipefd[1]); // 关闭写端
read(pipefd[0], buffer, sizeof(buffer));
printf("父进程收到:%s\n", buffer);
close(pipefd[0]);
wait(NULL);
}
}
/**
* 共享内存通信
*/
void shared_memory_demo() {
key_t key = ftok(".", 'a');
if (key == -1) {
perror("ftok");
exit(1);
}
// 创建共享内存
int shmid = shmget(key, 1024, IPC_CREAT | 0666);
if (shmid == -1) {
perror("shmget");
exit(1);
}
pid_t pid = fork();
if (pid == 0) {
// 子进程:写入共享内存
void *shared_mem = shmat(shmid, NULL, 0);
if (shared_mem == (void*)-1) {
perror("shmat");
exit(1);
}
strcpy((char*)shared_mem, "Hello from shared memory!");
printf("子进程写入共享内存\n");
shmdt(shared_mem);
exit(0);
} else {
sleep(1);
// 父进程:读取共享内存
void *shared_mem = shmat(shmid, NULL, 0);
if (shared_mem == (void*)-1) {
perror("shmat");
exit(1);
}
printf("父进程读取:%s\n", (char*)shared_mem);
shmdt(shared_mem);
// 删除共享内存
shmctl(shmid, IPC_RMID, NULL);
wait(NULL);
}
}
七、性能优化技巧
7.1 代码级优化
#include <stdio.h>
#include <time.h>
/**
* 性能优化技巧
*/
// 1. 循环展开
void loop_unrolling() {
int sum = 0;
int arr[1000];
// 普通循环
for (int i = 0; i < 1000; i++) {
sum += arr[i];
}
// 循环展开(每次处理4个元素)
int i;
for (i = 0; i < 1000 - 3; i += 4) {
sum += arr[i] + arr[i+1] + arr[i+2] + arr[i+3];
}
for (; i < 1000; i++) {
sum += arr[i];
}
}
// 2. 使用寄存器变量
void register_variable() {
// register关键字建议编译器将变量存储在寄存器中
register int count = 0;
for (register int i = 0; i < 1000000; i++) {
count++;
}
}
// 3. 位运算优化
int bitwise_optimization(int x, int y) {
// 乘以2的幂
int a = x << 3; // x * 8
int b = x >> 2; // x / 4
// 判断奇偶
int is_even = (x & 1) == 0;
// 取绝对值
int abs_val = (x ^ (x >> 31)) - (x >> 31);
return a + b;
}
// 4. 使用restrict关键字(C99)
void add_arrays(int *restrict a, int *restrict b, int *restrict c, int n) {
// restrict告诉编译器数组不重叠,可以优化
for (int i = 0; i < n; i++) {
c[i] = a[i] + b[i];
}
}
// 5. 分支预测优化
int branch_prediction(int x) {
// likely和unlikely宏(GCC扩展)
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
if (likely(x > 0)) {
return x * 2;
} else {
return -x;
}
}
// 6. 缓存友好访问模式
void cache_friendly() {
int matrix[1000][1000];
// 缓存友好:按行访问
for (int i = 0; i < 1000; i++) {
for (int j = 0; j < 1000; j++) {
matrix[i][j] = i + j;
}
}
// 缓存不友好:按列访问
for (int j = 0; j < 1000; j++) {
for (int i = 0; i < 1000; i++) {
matrix[i][j] = i + j;
}
}
}
八、知识体系图谱
C语言进阶知识
├── 指针深度剖析
│ ├── 多级指针与指针数组
│ ├── 函数指针与回调
│ ├── const与指针
│ └── 复杂声明解析
├── 内存管理
│ ├── 内存布局与对齐
│ ├── 内存池实现
│ └── 内存泄漏检测
├── 数据结构实现
│ ├── 链表(单/双/循环)
│ ├── 栈与队列
│ ├── 树与二叉树
│ └── 哈希表
├── 文件系统
│ ├── 随机访问与内存映射
│ ├── 目录遍历
│ └── 文件锁
├── 预处理与编译
│ ├── 高级宏技巧
│ ├── 多文件组织
│ └── Makefile
├── 系统编程
│ ├── 进程控制
│ ├── 信号处理
│ └── IPC通信
└── 性能优化
├── 代码级优化
├── 缓存优化
└── 编译器优化
进阶开发者的标志是能够理解程序在内存中的布局,能够设计高效的数据结构,能够写出可移植的系统级代码。当你能够用C语言实现一个简单的内存分配器,能够理解编译器的优化策略,能够在多进程环境中协调通信时,你已经成为了一名真正的C语言专家。
开源:
https://app-ad5sxofh8phd.appmiaoda.com