C语言面向对象基础
面向过程:
-
把问题分解成一系列的步骤
-
在函数里面一步步实现步骤
-
根据需求调用函数
面向对象:
-
把构成问题的事务分解成各个对象
-
调用对象里面的方法属性解决问题
面向对象三大特性:
-
封装性(父类、子类)
-
继承(将父类结构体放在子类结构体第一个位置即可)
-
多态:指针
文件IO
Linux内核
虚拟文件系统
抽象层,对文件的访问实际上对抽象层的访问。
抽象对象:封装了底层读写细节,使用C语言的多态来实现具体文件系统的操作
普通文件系统
-
ext4
-
fat32
-
ubifs
特殊文件系统
-
进程文件系统:procfs,挂载在/proc,存放进程相关信息
-
设备文件系统:devfs,挂载在/dev,存放外设设备
总结:指定普通文件系统多态到虚拟文件系统,app再调用虚拟文件系统中的函数,app也可以调用glibc,glibc再调用虚拟文件函数
文件描述符和打开模式
系统IO编程
-
直接调用Linux文件系统中函数
-
open write read lseek close • 进程控制:如 fork、clone、exit 、setpriority 等创建、中止、设置进程优先级的操作。 • 文件系统控制:如 open、read、write 等对文件的打开、读取、写入操作。 • 系统控制:如 reboot、stime、init_module 等重启、调整系统时间、初始化模块的系统操作。 • 内存管理:如 mlock、mremap 等内存页上锁重、映射虚拟内存操作。 • 网络管理:如 sethostname、gethostname 设置或获取本主机名操作。 • socket 控制:如 socket、bind、send 等进行 TCP、UDP 的网络通讯操作。 • 用户管理:如 setuid、getuid 等设置或获取用户 ID 的操作。 • 进程间通信:包含信号量、管道、共享内存等操作。
-
int fd; fd = open(filename,flags,mode); lseek(fd,offset,whence); write(fd,buf,len); read(fd,buf,len); close(fd); 文件描述符:fd,特殊的索引,file_struct结构体成员fd_array的数组下标 进程:每个程序 就是个进程
OPEN_close
//头文件 #include <sys/types.h> #include<sys/stat.h> #include<fcntl.h> fd = open("./b.txt",O_RDONLY|O_CREAT,0666); 标志位 含义 O_RDONLY 以只读的方式打开文件,该参数与 O_WRONLY 和 O_RDWR 只能三选一 O_WRONLY 以只写的方式打开文件 O_RDWR 以读写的方式打开文件 O_CREAT 创建一个新文件 O_APPEND 将数据写入到当前文件的结尾处 O_TRUNC 如果 pathname 文件存在,则清除文件内容
CLOSE
#include <unistd.h> int closh(int fd)
open_close.c
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> int main() { int fd; fd = open("./b.txt",O_RDONLY|O_CREAT,0666); if(fd < 0) { printf("OPEN erro\n"); } printf("fd:%d\n",fd); close(fd); return 0; }
Makefile
ARCH ?= x86 ifeq ($(ARCH),x86) CC=gcc else CC=arm-linux-gnueabihf-gcc endif TARGET=open_close BUILD_DIR=build SRC_DIR=. INC_DIR=. CFLAGS=$(patsubst %,-I%,$(INC_DIR)) INCLUDES=$(foreach dir,$(INC_DIR),$(wildcard $(patsubst)/*.h)) SOURCES=$(foreach dir,$(SRC_DIR),$(wildcard $(dir)/*.c)) OBJS=$(patsubst %.c,$(BUILD_DIR)/%.o,$(notdir $(SOURCES))) VPATH=$(SRC_DIR) $(BUILD_DIR)/$(TARGET):$(OBJS) $(CC) $^ -o $@ $(BUILD_DIR)/%.o:%.c $(INCLUDES) | create_build $(CC) -c $< -o $@ $(CFLAGS) .PHONY:clean create_build clean: rm -r $(BUILD_DIR) create_build: mkdir -p $(BUILD_DIR)
read_write函数
read
返回值:count(读取全部字节)、0-count、-1
#include <unistd.h> read(fd,*buff,size_count)
write
返回值:count(写入全部字节)、0-count、-1
#include <unistd.h> write(fd,*buff,size_count)
复制普通文件小实验
-
打开要复制的文件
-
创建新的文件
-
把源文件内容读到缓冲区,缓冲区内容写入新文件
-
循环第三步,直到读取字节为0,退出循环
-
关闭打开的文件
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> int main(int argc,char** argv) { int fd1,fd2; //定义源文件,新建文件 char buf[512]; //缓冲区 int read_size; //读取字节 if(argc != 3) //这里可以判断文件是否有源文件 { printf("argc erro\n"); return 1; } fd1 = open(argv[1],O_RDONLY); //只读源文件 fd2 = open(argv[2],O_WRONLY|O_CREAT,0666);//写+新建 if(fd1 < 0 || fd2 < 0) //判断源文件是否成功打开 { printf("open erro\n"); return -1; } while(1) //不断读取字节直到为0 { read_size = read(fd1,buf,521); if(read_size == 0) { break; } write(fd2,buf,read_size); } close(fd1|fd2); return 0; }
Iseek和sync函数
lseek:设置文件读写位置
#include <unistd.h> off_t lseek(int fd, off_t offset, int whence);
• SEEK_SET:offset 是一个绝对位置。
• SEEK_END:offset 是以文件尾为参考点的相对位置。
• SEEK_CUR:offset 是以当前位置为参考点的相对位置。
返回值偏移量、-1
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> int main() { int fd; fd = open("file",O_WRONLY|O_CREAT,0666); write(fd,"123",3); lseek(fd,100,SEEK_CUR); write(fd,"abc",3); close(fd); return 0; }
sync:
页缓存和回写
buff——页缓冲区——磁盘
功能;将页缓冲区强行写入磁盘中
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> int main() { int fd; fd = open("file",O_WRONLY|O_CREAT,0666); write(fd,"123",3); lseek(fd,100,SEEK_CUR); write(fd,"abc",3); sync(); close(fd); return 0; }
标准IO编程
C标准库实现了一个IO缓存区
-
调用glibc封装的函数
-
fopen() fclose() fwrite() fread() fseek() fflush() #include <stdio.h> FILE *fopen(const char *pathname, const char *mode); size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream); int close(int fd);//关闭文件 int fflush(FILE *stream);//fflush 函数用于把尚未写到文件的内容立即写出。 int fseek(FILE *stream, long offset, int whence); //fseek 函数用于设置下一次读写函数操作的位置
文件打开
• mode 参数用于指定文件的打开方式,注意该参数是一个字符串,输入时需要带双引号: •“r”:以只读方式打开,文件指针位于文件的开头。 •“r+”:以读和写的方式打开,文件指针位于文件的开头。 •“w”:以写的方式打开,不管原文件是否有内容都把原内容清空掉,文件指针位于文件的开 头。 •“w+”:同上,不过当文件不存在时,前面的“w”模式会返回错误,而此处的“w+”则会 创建新文件。 •“a”:以追加内容的方式打开,若文件不存在会创建新文件,文件指针位于文件的末尾。与 “w+”的区别是它不会清空原文件的内容而是追加。 •“a+”:以读和追加的方式打开,其它同上。
总结;
如库函数写入数据的文件操作 fwrite 最后也是执行了 write 系统调用,如果是写少量数据的话,直接执行 write 可能会更高效,但如果是频繁的写入操作,由于 f write 的缓冲区可以减少调用 write 的次数,这种情况下使用 fwrite 能更节省时间
文件IO五大模式
-
阻塞模式
-
非阻塞模式
-
IO多路复用
-
异步IO
-
信号驱动IO
控制LED灯设备
在 Linux 系统中,绝大多数硬件设备都有非常成熟的驱动框架,驱动工程师使用这些框架添加与
板子相关的硬件支持,建立硬件与 Linux 内核的联系,内核再通过统一文件系统接口呈现给用户,
用户通过对应的设备文件控制硬件。
对 于 LED 设 备,Linux 提 供 了 LED 子 系 统 驱 动 框 架, 在 Linux 内 核 源 码 中 的
“Documentation/leds/leds-class.txt”有相关的描述,它实现了一个 leds 类,用户层通过 sysfs
文件系统对 LED 进行控制。
控制硬件设备步骤
1、找出硬件设备所对应的设备节点文件
两个地方:
/dev目录下
对驱动程序熟悉的工程师可以使用,一个设备节点文件控制硬件全部特性
/sys目录下
业余工程师使用,一个设备节点文件只控制硬件的一个特性
严格来说,它下面的文件是Linux内核导出到用户空间的硬件操作接口
2、找出驱动程序规定的设备文件使用方式
LED灯程序
设备节点文件:/sys/class/leds
往brightness文件写入一个数值,就能控制led灯的亮度
led亮度值:0~255
echo 255 > /sys/class/leds/blue/brightness echo 0 > /sys/class/leds/blue/brightness在开发板里面编译程序之前,需要提前安装gcc和make工具
sudo apt install gcc/make
#include <stdio.h> #include <stdlib.h> #include <unistd.h> //ARM 开发板 LED 设备的路径 #define RLED_DEV_PATH "/sys/class/leds/red/brightness" #define GLED_DEV_PATH "/sys/class/leds/green/brightness" #define BLED_DEV_PATH "/sys/class/leds/blue/brightness" int main(int argc, char *argv[]) { FILE *r_fd, *g_fd, *b_fd; printf("This is the led demo\n"); //获取红灯的设备文件描述符 r_fd = fopen(RLED_DEV_PATH, "w"); if(r_fd < 0){ printf("Fail to Open %s device\n", RLED_DEV_PATH); exit(1); } //获取绿灯的设备文件描述符 g_fd = fopen(GLED_DEV_PATH, "w"); if(g_fd < 0){ printf("Fail to Open %s device\n", GLED_DEV_PATH); exit(1); } //获取蓝灯的设备文件描述符 b_fd = fopen(BLED_DEV_PATH, "w"); if(b_fd < 0){ printf("Fail to Open %s device\n", BLED_DEV_PATH); exit(1); } while(1){ //红灯亮 fwrite("255",3,1,r_fd); fflush(r_fd); //延时 1s sleep(1); //红灯灭 fwrite("0",1,1,r_fd); fflush(r_fd); //绿灯亮 fwrite("255",3,1,g_fd); fflush(g_fd); //延时 1s sleep(1); //绿灯灭 fwrite("0",1,1,g_fd); fflush(g_fd); //蓝灯亮 fwrite("255",3,1,b_fd); fflush(b_fd); //延时 1s sleep(1); //蓝灯亮 fwrite("0",1,1,b_fd); fflush(b_fd); } }