目录
- 结构体的字节对齐
- 预处理指令详解
- 文件操作基础
- Makefile自动化构建
- 总结
1. 结构体的字节对齐
字节对齐原理
- 内存对齐:CPU访问内存时,对齐的地址能提高效率。操作系统要求变量按类型大小对齐。
- 对齐规则:
- 每个成员的起始地址必须是
min(成员类型大小, #pragma pack(n))
的整数倍。 - 结构体总大小必须是最大成员对齐值的整数倍。
- 嵌套结构体需遵循相同规则。
- 每个成员的起始地址必须是
示例分析
示例1
struct Test {int a; // 4字节char b; // 1字节
};
// 默认对齐(假设为4字节):
// 总大小 = 4(int) + 3字节填充 + 1(char) = 8字节
示例2(嵌套结构体)
struct A {double a; // 8字节short b; // 2字节
};struct Test {char a[20]; // 20字节int c; // 4字节struct A d; // 12字节(8+4填充)char b; // 1字节
};
// 总大小:20 + 4 + 12 + 1 + 3填充 = 40字节
调整对齐方式
#pragma pack(n)
:手动设置对齐粒度。#pragma pack(1) // 紧凑存储 struct Test {char a; // 1字节int b; // 4字节(无填充) }; #pragma pack() // 恢复默认
2. 预处理指令详解
预处理阶段
- 作用:宏定义、头文件包含、条件编译等。
- 流程:预处理 → 编译 → 汇编 → 链接。
头文件包含
- 区别:
#include <stdio.h>
:系统头文件。#include "test.h"
:当前目录或自定义路径。
头文件重复包含防护
#ifndef _TEST_H_
#define _TEST_H_
// 头文件内容
#endif
宏定义与条件编译
无参宏
#define PI 3.14
#undef PI // 取消定义
有参宏
#define MUL(x,y) ((x)*(y)) // 避免运算优先级问题
#define ADD(x,y) (x + y)
条件编译
#ifdef DEBUGprintf("Debug mode\n");
#elseprintf("Release mode\n");
#endif
3. 文件操作基础
文件操作模式
模式 | 描述 | 示例模式 |
---|---|---|
r | 只读文本文件 | fopen("file.txt", "r") |
w | 只写文本文件(覆盖) | fopen("file.txt", "w") |
a | 追加文本文件 | fopen("file.txt", "a") |
rb | 只读二进制文件 | fopen("file.dat", "rb") |
wb | 只写二进制文件(覆盖) | fopen("file.dat", "wb") |
字符与字符串读写
fgetc/fputc
FILE *fp = fopen("file.txt", "w");
fputc('A', fp); // 写入字符'A'
fclose(fp);
feof判断文件结束
char ch;
FILE *fp = fopen("file.txt", "r");
while ((ch = fgetc(fp)) != EOF) { // EOF表示文件结束printf("%c", ch);
}
fclose(fp);
fgets/fputs按行读写
// 写入
fputs("Hello World\n", fp);
// 读取
char buf[256];
fgets(buf, sizeof(buf), fp); // 读取一行,自动添加'\0'
格式化读写(fprintf/fscanf)
// 写入
fprintf(fp, "a=%d,b=%.2f\n", 100, 3.14);
// 读取
int a;
float b;
fscanf(fp, "a=%d,b=%f", &a, &b);
二进制文件操作(fread/fwrite)
typedef struct {char name[20];int id;
} STU;STU students[3] = { /* 初始化数据 */ };
// 写入
FILE *fp = fopen("data.dat", "wb");
fwrite(students, sizeof(STU), 3, fp);
fclose(fp);// 读取
STU read_data[3];
fp = fopen("data.dat", "rb");
fread(read_data, sizeof(STU), 3, fp);
fclose(fp);
文件随机读写
-
定位文件指针:
fseek(fp, 50, SEEK_SET); // 从文件头移动50字节 fseek(fp, -50, SEEK_END); // 从文件尾回退50字节
-
获取当前位置:
long pos = ftell(fp); // 当前位置偏移量 rewind(fp); // 快速回到文件开头
4. Makefile自动化构建
Makefile基础规则
# 目标依赖规则
main: main.o add.o sub.ogcc main.o add.o sub.o -o mainmain.o: main.cgcc -c main.c
变量与自动变量
- 普通变量:
CC = gcc CFLAGS = -Wall -g
- 自动变量:
$@
:目标文件名$^
:所有依赖文件$<
:第一个依赖文件
模式规则与函数
# 通用编译规则
%.o: %.c$(CC) -c $< -o $@ $(CFLAGS)# 查找所有.c文件
SRCS = $(wildcard *.c)
OBJS = $(patsubst %.c, %.o, $(SRCS))
多文件项目示例
DIR_SRC = ./src
DIR_OBJ = ./obj
SRCS = $(wildcard $(DIR_SRC)/*.c)
OBJS = $(patsubst $(DIR_SRC)/%.c, $(DIR_OBJ)/%.o, $(SRCS))main: $(OBJS)$(CC) $^ -o main$(DIR_OBJ)/%.o: $(DIR_SRC)/%.c$(CC) -c $< -o $@ -I./include.PHONY: clean
clean:rm -rf $(DIR_OBJ)/*.o main
5. 总结
- 结构体对齐:通过
#pragma pack
优化内存布局,避免内存浪费。 - 预处理:宏定义提升代码复用性,条件编译增强跨平台兼容性。
- 文件操作:区分文本与二进制模式,灵活使用
fseek
和ftell
实现随机读写。 - Makefile:自动化构建简化编译流程,支持多文件项目管理。
希望这篇博客能帮助你系统掌握C语言核心知识点!如果有疑问或需要进一步解释,欢迎在评论区交流!