嵌入式系统分为三层 应用层(C、java、数据结构和算法、Android等)再往为内核层(linux高级编程,学好这部分才能利用linux 系统做事情)再往下为硬件层(和之前搞单片机的那套系统差不多了)。
linux高级编程:其实就对linux内核向用户空间提供的许多函数或接口的学习。即函数功能、参数、返回值。
IO知识点:IO针对的是应用层与内核层的间输入与输出。
注:linux命令都是由linux内核函数接⼝所编写的程序来实现的。
文件IO:
注: 文件描述符?内核采用ID号的形式标识一个文件。那么文件ID号在每个用户的程序中怎么映射的呢?就是文件描述符。
当一个程序开始运行时,它一般会有3个已经打开的文件描述符,就是
0:标准输入
1:标准输出
2:标准错误
那些数学(即0、1、2)就是文件描述符,因为在Linux上一切都是文件,所以标准输入(stdin),标准输出(stdout)和标准错误(stderr)也可看作文件来对待。
open()的返回值就是这个ID号。文件权限标识:
参 数 | 说 明 | 参 数 | 说 明 |
S_IRUSR | 所有者拥有 读权限 | S_IXGRP | 群组拥有执 行权限 |
S_IWUSR | 所有者拥有 写权限 | S_IROTH | 其他用户拥 有读权限 |
S_IXUSR | 所有者拥有 执行权限 | S_IWOTH | 其他用户拥 有写权限 |
S_IRGRP | 群组拥有读权限 | S_IXOTH | 其他用户拥 有执行权限 |
S_IWGRP | 群组拥有写权限 |
|
|
文件权限标志也可以使用加权数字表示,这组数字被称为umask变量,它的类型是mode_t,是一个无符号八进制数。umask变量的定义方法如表13.4所示。umask变量由3位数字组成,数字的每一位代表一类权限。用户所获得的权限是加权数值的总和。例如764表示所有者拥有读、写和执行权限,群组拥有读和写权限,其他用户拥有读权限。设置的值mode & ~(取反) umask(系统值),这样才得出我们设置的文件真正的权限值,或者将umask设置为0
表13.4 umask变量表示方法
加 权 数 值 | 第1位 | 第2位 | 第3位 |
4 | 所有者拥有 读权限 | 群组拥有读权限 | 其他用户拥 有读权限 |
2 | 所有者拥有 写权限 | 群组拥有写权限 | 其他用户拥 有写权限 |
1 | 所有者拥有 执行权限 | 群组拥有执行权限 | 其他用户拥 有执行权限 |
标准IO:
与文件IO的不同?
文件IO是直接调用内核提供的接口函数,头文件是unistd.h
标准IO是调用C语言的库函数的方式间接调用内核的系统函数,头文件是stdio.h
提供三种缓冲
1.全缓冲:在缓冲区写满时输出到指定的输出端. 比如对磁盘上的文件进行读写通常是全缓冲的.
2.行缓冲:在遇到'\n'时输出到指定的输出端. 比如标准输入和标准输出就是行缓冲, 回车后就会进行相应的I/O操作.
3.无缓冲:有什么就输出什么. 比如标准错误输出, 出错时立即显示出来.stderr就是了。
设置缓冲方式的函数有两个,分别为setbuf,setvbuf
可用fflush立即输出,不管缓冲区是否达到输出标准
打开、关闭
定义在/usr/include/libio.h
1.FILE *fopen(const char *restrict pathname, const char *restrict type)
第一个参数为文件的路径,
第二个参数为打开的方式: r/rb只读; w/wb只写; a/ab添加; r+/ra+读写; w+/wa+读写; a+/ab+文件尾添加读写
a:追加
w:会重新创建一个
+读写
b:打开二进制文件
2.int fclose(FILE *fp)成功返回 0,失败返回EOF=-1,
关闭打开的文件流, 释放缓存;在文件被关闭前会刷新(将缓存中的数据放到内核调用的硬件上面去)缓存。
行缓存读写函数,即遇到"\n"或写满时会调用系统函数
fgets/fputs
scanf/printf
gets/puts默认对应终端窗口的输入输出
注意: puts会在行尾插入添加一个'\n', 所以当我们用puts打印文件时,每行显示时都有两个'\n'(除最后一行外), 也就是每行内容下面都会有一个空行
注:
char * fgets(char *s,int size,FILE *stream);
第一个参数:读到哪里去
第二个参数:读多少个字节
第三个参数:从哪里读 成功返回s(缓存的地址),若已经到文件结尾或失败返回null
int fputs(const char *s,FILE *stream);
第一个参数:缓存,写什么内容
第二个参数:写到哪里去
成功为非负值,失败返回EOF -1.
刷新缓存函数 fflush(FILE *fp)把缓存中的数据强制写到内核中。
无缓存:标准出错流stderr
调整读写位置函数:
fseek()参数与lseek()参数是一样的,不同的是返回值
lseek返回当前文件位置
fseek返回0,失败返回-1
rewind(FILE *fp)文件的位置为开始相当于(void )fseek(fp,0 SEEK_SET);
ftell()取得当前文件的位置指针
另一对行缓存读写函数 gets()和puts()
char *gets(char *s)//只从标准的输入读,同时也没有缓存的大小,存在越界的可能有BUG
与fgets 不同:gets并不将新行符存入缓存
int puts(const char *s)//只能写到标准的输出
与fputs不同:puts在输出的时候会添加一个\n
另一对比较常用的读写函数 printf sprintf fprint
int fprintf(FILE *stream,“字符串格式");//可以输出到文件也可以输出到显示器printf只能输出到显示器
int sprintf(str *,“字符串格式”);//输出格式内容到字符串中;把要写的东西写到一个字符串中。
一个字符的读写函数
int fgetc(FILE *fp)//从文件中读取一个字符
参数:文件流
返回:正确为读取的字符,到文件结尾或出错返回EOF
int fputc(int c,FILE *fp)//写一个字符到文件中
参数:第一个参数为要写的字符,第二个参数为文件流
返回:正确返回输入的字符,出错返回EOF
如何区分是到文件尾还是读写出错??
int feof(FILE *stream)//判断是否到文件结尾
参数:文件流
返回值:到文件结尾返回为非0,没有则返回0.
int ferror(FILE *stream)//判断是否读写错误
参数:文件流
返回值:是读写错误,返回为非0,不是则返回0
void clearerr(FILE *stream)//清除流错误
参数为:文件流
全缓存读写函数
size_t fread(void *put,size_t size,size_t nmemb,FILE *stream);
size_t fwrite(const void *ptr,size_t size,size_t nmemb,FILE *stream);
第一个参数buf ;写的内容
第四个参数stream 写到哪里去
第二个参数:size;写的内容中,每一个单元所占的字节数
第三个参数:nmemb:写的内容中,有多少个单元数。
总共写多少个字节,=size *nmemb
返回值:实际读写单元数。
linux静态库和动态库(共享库)的制作
静态库以libXX.a结尾,编译时就加载到程序中。
动态库以libXX.so结尾,动行时将库加载到可执行程序中,运行环境必须提供相应的外部库。
静态库的制作:
1、生成目标文件:gcc -c file.c
2、静态函数库创建命令 ar
ar -cr lib file.a file.o
-c :create的意思
-r : replace的意思,表示当插入的模块file.o已经存在libfile.a中,则覆盖,反之ar显示一个错误消息。
使用:gcc XX.c -L. -lxx //注:XX指要编译的c文件 xx是静态库文件名 -l已经指明是静态库,所以直接加文件名就可以
不用再加.a
删除.a文件后,main依然可以运行,因为静态库内容已经整合进去了
动态库的制作:
1、生成目标文件:gcc -c file.c
2、gcc -shared -fpic -o libfile.so file.o
-fpic: 产生位置无关代码
-shared: 生成共享库
使用:gcc -o out main.c -L. -lfile
此时还不能立即./out,因为在动态函娄库使用时,默认会查找usr/lib 目录下的动态函数库
第一种方法:
将libaddsu.so放到usr/lib或.lib中去。
第二种方法:假设libfile.so在/home/linux/file相当于windows下环境变量的设置
exprot LD_LIBRARY_PATH=/hom/linux/addsub //代表当前.so所在的路径。 $LD_LIBRARY_PATH
第三种方法:
在/etc/ld.so.conf文件里加入我们生成的库的目录,然后/$bin/ldconfig
/etc/ld.so.conf是非常重要的目录,存放着是链接咕咕和加载器搜索共享库时要检查的目录,默认是从/usr/lib/ 或/lib中读取的,所以可以把库目录加入到这个文件中执行。
目录IO:对目录进行操作
#include <sys/types.h>
#include <dirent.h>
1、创建目录
int mkdir(const char *path,mode_t mode)
path为欲创建的目录的文件路径
mode为该目录的访问权限
成功则返加0,失败返回-1。
生成的目录权限仍和unmask有关系。
opendir
DIR *opendir(const char *pathname);//打开目录及路径
返回值:成功返回目录流指针,出错返回NULL
readdir
struct dirent *readdir(DIR *dr)//目录流指针
成功为struct dirent指针,若在目录尾或出错返回NULL
struct dirent 定义在头文件dirent.h中
struct dirent
{
ino_td ino://inode号
char d_name[NAME_MAX+1];//文件名
}
2、rewinddir:重置读取目录的位置为开头
void rewinddir(DIR *dr)
参数:目录流指针
long relldir(DIR *dirp)
参数:目录流指针
返回目录流当前位置
void seekdir(DIR *dirp,long loc)//类似于文件定位函数fseek(),在目录流上设置下一个readdir()操作的位置
参数:目录流指针和偏移量
4、closedir
int closedir(DIR *dr)
参数:目录流指针
成功返回0,出错返回-1