C语言文件操作与宏定义常见问题解析
文件
文本文件
(ASCII文件)
二进制文件
(二进制文件)
文件操作
注意事项
- fputs 函数不能写入换行符
- fscanf 读取时必须传地址
为什么 fclose 必须调用?
- 要刷新缓冲区
- 要释放文件资源
fgets 和 fscanf 的区别
- fputs 专门写字符串
- fprintf 专门写格式化数据
文件定位操作
- fseek(fp, offset, whence)
fseek(fp,-3,SEEK_END); 表示移动到文件末尾的第3个字节
ftell(fp) 追加模式下,打开文件时指针处于文件末尾,ftell返回文件长度
计算文件的大小使用
fseek(fp,0,SEEK_END)
ftell(fp);文件mode列表
位置指针
文件指针:文件指针是一个指向文件位置的指针,用于记录当前文件操作的位置。
判文件结束函数 feof()
文本文件可以使用EOF 作为文件结束标志;二进制文件则使用feof进行函数判断文件是否结束,如果返回值为非0,则文件结束,否则返回值为0。
读取输入返回值
预处理
编译的流程:预处理 -> 编译 -> 汇编 -> 链接
防止重复包含
#ifndef TEST_H
#define TEST_H
// 内容
#endif宏函数
#undef 有什么作用?
取消宏定义
使宏失效
方便重新定义
避免宏污染库操作
静态库生成
gcc -c add.c sub.c
ar rcs libmylib.a add.o sub.o
# rcs 表示 r:插入/替换文件 c:创建库文件 s:生成索引(很重要)
gcc main.c -L. -lmylib -o app动态库生成
gcc -fPIC -c add.c -o add.o
gcc -shared -o libmylib.so add.o sub.o
gcc main.c -L. -lmylib -o app- 注意:如果在程序编译/运行中链接了库文件,系统会到指定的目录下去查找库文件, 一般查找顺序如下:
- -L 指定的路径
- LD_LIBRARY_PATH
- /etc/ld.so.conf里的路径
- 默认系统路径: /lib /usr/lib
- 建议直接将库文件放置在 默认系统路径 ,可确保编译和运行时系统可以正确 加载库文件。
手动加载库文件
dlfcn 库函数, 使用时需要链接 -ldl
- dlopen() 返回值:*handle, 失败返回NULL,可以使用dlerror() 获取错误信息
- dlsym() 返回值:*func,失败返回NULL,可以使用dlerror() 获取错误信息
- dlclose()
- handle 句柄
位运算
- 位运算是对 二进制位(bit) 进行操作的运算
- 位运算符:& | ^ ~ << >>
- 1)将某个数据二进制位(n1,n2…)清零
a &= ~(1<<n1) - 2)获取某个数据指定二进制位(n1,n2…)的数据
(a & (1 << n1)) >> n1(a >> n) & 1 - 3)将某个数据二进制位(n1,n2…)置位
a |= (1<<n1) - 4)将某个数据二进制位(n1,n2…)反转
a ^= (1<<n1)
位端
- 位端 CPU存储多字节数据时:字节存放顺序不同
- 浮点型类型不能做位段;
- 位段不能跨越内存单元
- 位段二进制位数不能超过类型长度
- 位段是无法获取地址的。
- C语言允许定义无名位段,无名位段无法访问
- 无名位段设置长度为0, 强制下一个位段存储于下一个内存单元
- 不能定义位段数组。
- 位段数据要考虑主机字节序
内存地址与位权的高低
内存地址的高低:看十六进制数值的大小。比如 0x101 比 0x100 大,所以 0x101 是高地址,0x100 是低地址。 位权的高低:看二进制数的书写位置。左边是高位(权重最大),右边是低位(权重最小)。例如在 10000001 中,左边的 1 代表 128(高位),右边的 1 代表 1(低位)。
大小端模式 (Endianness)
这是指多字节数据(如 int)在内存中的存储顺序: 小端模式 (Little-Endian):“低存低”。数据的低位字节存放在内存的低地址处。目前主流的 x86/x64 电脑都是小端模式。 大端模式 (Big-Endian):“高存低”。数据的高位字节存放在内存的低地址处。符合人类阅读习惯,常用于网络传输和部分嵌入式设备。 判断方法:利用联合体(union)或指针强转,将整数 1 存入内存,然后读取其最低地址的第一个字节。如果读到 1 就是小端,读到 0 就是大端。
联合体 (Union)
核心特性:联合体内的所有成员共享同一块内存空间,并且都是从这块内存的起始位置(低地址)开始存放。 巧妙应用:正是因为它共享内存且从低地址对齐的特性,我们才能用一个单字节的 char 去“偷看”一个四字节 int 在低地址处到底存了什么,从而判断出系统的字节序。