• C POSIX Library: https://zh.wikipedia.org/wiki/C_POSIX_library
  • opengroup headers doc:http://pubs.opengroup.org/onlinepubs/9699919799/idx/head.html
  • 找到一个搜索POSIX头文件的方法,在dash里面加搜索引擎,地址为http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/{query}.h.html。这样就可以快速查询到header的定义
  • 另外linux man page里面也有如 sys_types

chapter1基础

  • POSIX标准,由IEEE开发的一套标准,保证所编制的应用程序在不同平台都可以运行和移植。linux,unix,mac都符合此标准
Linux内核的主要模块
  • 进行调度SCHED, Linux下进程调度有三种策略
    • SCHED_OTHER:时间片轮转调度
    • SCHED_FIFO:针对实时性要求高,时间段的进程调度策略,先进入先调度
    • SCHED_PR:实时性要求高,运行时间长的进程调度策略。与SCHED_OTHER类似,不过SCHED_PR优先级要高很多
      Linux采用有条件可剥夺的调度方式。普通进程使用SCHED_OTHER, 实时进程可以剥夺普通进程
  • 内存管理:虚拟内存
  • 文件系统:虚拟文件系统
  • 网络接口:网络协议和驱动程序
  • 进程通信:管道,信号,消息队列,共享内存,套接字

chapter2编程环境

gcc
  • 头文件先后查找目录
    • /usr/local/include
    • /usr/lib/gcc/…/include
    • /usr/include
  • 库文件

    • /usr/lib/gcc…
    • /lib/…/
    • /lib/
    • /usr/lib
  • 两个源文件编译成一个可执行文件 gcc -o test string.c main.c

  • 或者是先编译成目标文件,再进行链接 gcc -c string.c main.c,再gcc -o test string.o main.o
  • 编译成汇编语言gcc -S string.c
静态库
  • 静态库是obj文件的一个集合,静态库以.a为后缀,优点是在不用重新比那一程序库代码的情况下,进行程序的重新链接。
  • 另一个优势是不用开放源码,可以模块化开发
  • 理论上静态库执行比动态库要快
动态链接库
  • 动态链接库是程序运行时加载的库,在动态链接库安装后,所有的程序都可以用动态库来运行程序
  • linux中动态库为.so的后缀
  • 动态链接库的配置文件在/etc/ld.so.conf指定了系统动态库的目录
  • ldconfig -p可以列出当前使用的动态库的缓存
使用静态库或动态库
  • gcc -o test main.c -L./ -lstr -L指定路径,-l指定链接库函数。这个时候他会去寻找libstr.a或者libstr.so
  • 当使用动态库的时候,程序连杰的动态库需要在系统目录下才行,解决的话
    • 将动态链接库的目录放到程序搜索路径中 export LD_LIBRARY_PATH=/a/b $LD_LIBRARY_PATH
    • 使用ld-linux.so.2加载程序
  • 如果搜索目录同时又动态库和静态库,那么会优先使用动态库
动态加载库

使用动态加载库可以用程序来控制什么时候加载
主要用到ldopen, dlerror, dlsym, dlclose等

GCC常用选项
  • -Wall 打开所有gcc能提供的,常用的警告信息
  • -g 包括调试信息
  • -static仅选用静态库进行连接
Makefile

对于一个例子,包含add.h, add.c, sub.h, sub.c, main.c几个文件,main.c引用了add.h和sub.h

  • 一种方式 gcc -c 每一个.c文件 生成.o文件,然后gcc -o output add.o sub.o main.o 生成output
  • 建立makefile
Makefile的规则
1
2
3
TARGET ...: DEPENDENCES...
COMMAND
...
1
2
main.o:main.c add/add.h sub/sub.h
gcc -c -o main.o main.c -Iadd -Isub
  • 其中I为寻找headerFile的目录
  • 模式匹配:https://www.kancloud.cn/kancloud/make-command/45594
Makefile使用变量
  • 自定义变量如定义 OBJS = sub.o add.o main.o,就可以使用 gcc -o cacu $(OBJS)
  • 可以定义自己的变量比如CC = gcc CFLAGS = -Isub -Iadd RM = rm -f
  • 自动变量

    • $@指代当前目标

      1
      2
      3
      4
      5
      6
      7
      a.txt b.txt: 
      touch $@
      等同于
      a.txt:
      touch a.txt
      b.txt:
      touch b.txt
    • %< 指代前置变量

    • %.o:%.c将所有的.o替换成.c
    • $^ 依赖项中,所有不重复的依赖文件,以空格分开
搜索路径

VPATH=path1:path2:...
冒号分隔路径名称

递归make
1
2
3
4
add:
cd add && $(MAKE)
add:
$(MAKE) -C add
总控Makefile

export OBJSDIR = ${shell pwd}/.objs
生成当前目录的路径字符串,并赋值给objsdir
如果子目录有makefile ,也可以在总makefile中递归调用子目录的make

函数
  • $(wildcard *.c) 所有.c文件
  • $(patsubst %.c,%.o add.c)将所有的.c替换成.o
  • $(patsubst %.c,%.o $(wildcard *.c)) 替换所有.c为.o
  • FILES = $(foreach dir,$(DIRS), $(wildcard $(dir)/*.c)) 查找所有.c文件,赋值给FILES
gdb
  • 编译的时候-g这样可以使用gdb调试这个应用程序
  • 使用的时候gdb和lldb类似

chapter3文件系统

Linux下的文件系统

######Linux下文件的类型

  • 普通文件:如保存在磁盘上的文件,可执行文件,文件夹
  • 字符设备文件:能够像文件一样被访问的设备,如控制台,串口,键盘, ls -all的时候第一个字符为c
  • 块设备文件:如磁盘/CD-ROM等,这类一般支持随机存取和寻址,并且使用缓冲区。如/dev/sdb .ls -all的时候第一个字符为b。设备文件在ls的时候第五个为主设备号码,主设备号码表示存取这个设备的内核驱动
  • socket文件:网络通信的方式。如/tmp/mysql.sock
文件系统的创建
  • 当前磁盘情况的查看和分区fdisk
1
2
3
4
5
6
7
8
9
10
11
12
yudun1989@ubuntu:/dev$ sudo fdisk -l
Disk /dev/sda: 20 GiB, 21474836480 bytes, 41943040 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x707b6124

Device Boot Start End Sectors Size Id Type
/dev/sda1 * 2048 39845887 39843840 19G 83 Linux
/dev/sda2 39847934 41940991 2093058 1022M 5 Extended
/dev/sda5 39847936 41940991 2093056 1022M 82 Linux swap / Solaris
  • 挂载分区:mount, 如建立一个test目录,将sdb挂载上去 mount /dev/sdb1 /test
  • 查看分区挂载情况:df
  • 挂载也可以挂载其他的文件系统,如网络文件系统等.
索引节点innode
  • 文件包含两个内容,用户数据和元数据,元数据是文件的附加属性如文件大小,创建时间,所有者信息等。
  • 系统和程序通过innode号找到正确的文件数据块
  • 使用ls -i查看文件的innode号码
  • 硬链接:一个inode号对应多个文件名(类似于一个文件使用了多个别名, 只能对文件创建不能对目录创建)
  • 软连接:软连接有自己的文件属性和权限,可以对不存在的文件或者目录创建软连接
设备文件的简单操作
1
2
yudun1989@ubuntu:~$ echo "test">/dev/stdout
test
虚拟文件系统VFS
  • 虚拟文件系统可以看做是ext2或者vfat上的一层抽象文件系统,里面有节点索引缓存,目录缓存等。
  • 利用虚拟文件系统,可以实现比如write函数在ext2和vfat上都可以运行。

//TODO:暂时没有精力去细读VFS的具体内容

文件的通用操作方法
文件描述符
  • 当打开或创建一个文件的时候,内核空间创建相应的结构,并生成一个整形的变量给用户空间的对应进程。进程用这个文件描述符对文件进行操作。
  • 文件描述符的值仅在同一个进程有效,不同进程的同一个描述符可能不是同一个设备或者文件。
  • linux有三个已经分配的描述符:0为标准输入(stdin),1位标准输出(stdout),2为标准错误(stderr)
open/create

http://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html

  • 函数为int open(const char *pathname, int flags, mode_t mode), 其中mode_t在sys_types.h里面, flags在fcntl.h里面, fcntl为file control options
  • close函数为int close(int fd),因为在打开文件的时候如果不关闭,那么在文件描述符为1024的时候回因为超过系统可分配最大值发生错误
  • read函数为ssize_t read(int fd, void *buf, size_t count);, buf是一个指针,指向缓冲区开始位置, count表示要读取的字节量。
  • write函数为ssize_t write(int fd, const void *buf, size_t count);
  • lseek 文件的偏移量是一个非负整数,表示从文件开始到当前位置的字节数。off_t lseek(int fd, off_t offset, int whence);.生成了一个有空洞的文件之后,可以用od命令查看文件的十六进制。
  • stat获取文件状态,主要依赖于结构struct_stat,包含文件块大小,保护设置,硬链接数等
  • mmmap将文件映射到内存中,这样就可以不用read等,可以更快。
  • fcntl用来获得打开的文件的性质
  • ioctl用来控制IO设备
  • ioctlfcntl是内核和应用层直接通信的一种方法