当前位置: 首页 > news >正文

C语言核心知识点整理:结构体对齐、预处理、文件操作与Makefile

目录

  1. 结构体的字节对齐
  2. 预处理指令详解
  3. 文件操作基础
  4. Makefile自动化构建
  5. 总结

1. 结构体的字节对齐

字节对齐原理

  • 内存对齐:CPU访问内存时,对齐的地址能提高效率。操作系统要求变量按类型大小对齐。
  • 对齐规则:
    1. 每个成员的起始地址必须是min(成员类型大小, #pragma pack(n))的整数倍。
    2. 结构体总大小必须是最大成员对齐值的整数倍。
    3. 嵌套结构体需遵循相同规则。

示例分析

示例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 DEBUG
    printf("Debug mode\n");
#else
    printf("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.o
    gcc main.o add.o sub.o -o main

main.o: main.c
    gcc -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优化内存布局,避免内存浪费。
  • 预处理:宏定义提升代码复用性,条件编译增强跨平台兼容性。
  • 文件操作:区分文本与二进制模式,灵活使用fseekftell实现随机读写。
  • Makefile:自动化构建简化编译流程,支持多文件项目管理。

希望这篇博客能帮助你系统掌握C语言核心知识点!如果有疑问或需要进一步解释,欢迎在评论区交流!


相关文章:

  • GPT文生图模型新玩法
  • DFS和BFS的模版
  • Linux 基础入门操作 前言 VIM的基本操作 2
  • Java logback框架日志输出中文乱码的解决方案(windows)
  • 【Easylive】定时任务-每日数据统计和临时文件清理
  • JavaWeb 课堂笔记 —— 04 Ajax
  • 我提了一个 Androidx IssueTracker
  • [QMT量化交易小白入门]-四十二、五年年化收益率26%,当日未成交的下单,取消后重新委托
  • PHP开发效率提升利器:通义灵码在VSCode中的应用与技巧
  • Model Context Protocol(MCP)介绍
  • CPP杂项
  • 下载firefox.tar.xz后如何将其加入到Gnome启动器
  • 《Spring Boot+策略模式:企业级度假订单Excel导入系统的架构演进与技术实现》
  • vue3的一些新特性
  • vcs中的looprepprt
  • kafka存储原理
  • 定积分__
  • C应用常见的编程错误
  • java入门
  • LeetCode:有效的括号
  • 习近平圆满结束对俄罗斯国事访问并出席纪念苏联伟大卫国战争胜利80周年庆典
  • 工程院院士葛世荣获聘任为江西理工大学校长
  • 【社论】职业上新,勇于“尝新”
  • 以总理内塔尼亚胡称决心彻底击败哈马斯
  • 视频丨习近平主席出席俄方在机场举行的迎宾仪式
  • 外交部:应美方请求举行贸易代表会谈,中方反对美滥施关税立场没有变化