《Linux 环境C程序设计》阅读笔记
《Linux 环境C程序设计》阅读笔记
Chapter 1
- GNU项目
GNU项目是1983年理查德·斯托曼(Richard Stallman)创立的,最初的目标是通过使用必要的工具从源代码开始创建一个自由的类UNIX操作系统。
GNU花了10年的时间创建了GCC编译器、Emacs编辑器等多个工具。这些工具的改进版本和衍生品必须遵循GPL协议。但是在20世纪80年代缺少最关键的组件,即操作系统核心,直到Linux诞生。
2. 开源软件与免费软件
免费软件是以二进制的形式发布的 ,可以使用,但是无权修改。开源软件是以源代码的形式发布的,遵循GPL协议,可以对其进行修改。
3. Linux内核与版本Linux内核是操作系统的核心文件,与其他程序进行组合,Linux构成了许多的版本。嵌入式Linux常用于较小的电子设备操作,而计算机中常用的是Linux桌面版和Linux企业版。
4. Linux内核
内核主要由中断服务程序,调度程序,内存管理程序,网络和进程间通信等系统程序组成。内核是独立于普通的程序,运行于内核态,拥有受保护的内存空间和访问硬件设备的所有权限。系统态和被保护起来的内存空间称为内核空间。
5. 支持的硬件平台
linux内核支持当前所有的主流硬件平台,能运行在各种架构的服务器,如Intel的IA64,Compaq的Alpha,Sun的Sparc/Sparc64,SGI的Mips,IBM的S396,也能运行在几乎全部的工作站,如Intel的x86,Apple的PowerPC。也支持嵌入式系统和移动设备,如ARMLinux内核短小精湛且功能全面。
6. 硬盘分区
主要有3种分区类型:主分区,扩展分区和逻辑分区。一块硬盘上最多有4个主分区和一个扩展分区。
linux下常用的 文件系统是Ext3(Ext4),Swap。Ext3专门为linux设计,拥有极快的速度和极小的CPU占有率。也是一种日志式文件系统,可以进行回溯。
第3章 Linux GCC/G++编译器与调试器
1. GCC/G++编译器
常用的编译选项:
编译选项 | 说明 |
-c | 只进行预处理、编译和汇编,生成".o"文件 |
-S | 只进行预处理和编译,生成".s"文件 |
-E | 只进行预处理,产生预处理后 结果到标准输出 |
-C | 预处理时不删除注释信息,常与-E同时使用 |
-o | 指定目标名称,常与-c、-S同时使用默认是".out" |
-include file | 插入一个文件,等同源码中的#include |
-Dmacro[=defval] | 定一个宏 |
-Umacro | 取消宏定义 |
-Idir | 优先在选项后的目录中查找包含头文件 |
-lname | 链接后缀为".so"的动态链接库来编译程序 |
-Ldir | 指定编译搜索库的路径 |
-O[0-3] | 编译器优化,数值越大优化越高,0没有优化 |
-g | 编译器加入debug信息 |
-pg | 编译器加入信息给gprof |
-share | 使用动态库 |
-static | 禁止使用动态库 |
2. 程序与进程
进程是一个具有独立功能的程序关于某个数据集合的一次可以并发执行的运行活动,是处于活动状态的程序。进程作为构成系统的基本元件,不仅是系统内部独立运行的实体,也是独立竞争资源的实体。
进程都有PID,init进程拥有PID=1,它负责管理其他进程。
- 类属指针
类属指针是一种能够同时支持所有数据类型的指针,函数原型中常用的void*类型即为类属指针。ANSIC标准常用类属指针代替函数参数中的其他指针,使同一个函数能偶支持多种数据类型。
- 原始系统数据类型
在函数原型中以"_t"结尾的类型被称为元素系统数据类型。原始系统数据类型定义在头文件sys/type.h中,以typedef操作符加以定义。原始系统数据类型是目标系统数据类型结构的接口,在不同的操作系统中,其字长会有变化。
第9章 函数
1. Linux系统常用的C语言函数库
函数库 | 说明 |
libdbus | D-Bus进程间通信机制函数库,用于两个应用程序相互联系和交互信息 |
libpthread | POSIX线程库,用于多线程通信 |
libthread | Solaris线程库,用于多线程通信 |
libnet | 网络开发库,用于实现和封装了数据包的构造和发送过程 |
libcurl | 客户端url传输库,用于数据下载和上传 |
libpq | PostgreSQL数据库接口,用于操作PostgreSQL数据库 |
Glib | GTK+和GNOME的基础,提供了具备可移植性的数据结构 |
GTK+ | 图形化用户界面构件库,用于图形界面开发 |
GStreamer | GStreamer多媒体框架函数库,用于开发多媒体播放程序 |
libgrade | Grade开发库,用于所见即所得方式的图形界面开发 |
Linux系统一般将函数库放在/lib和/usr/lib目录下,GCC会自动搜索。pkgconfig程序为配置函数库的路径提供了方便,它用于在编译时指定函数库的路径。
安装完pkgconfig软件后,可以使用pkg-config –list-all来查看已安装的函数库和相关信息。
第13章 Linux中的文件操作
1. Linux 中的文件管理
C语言的文件管理功能有3种常用的实现途径。第一种是直接进行文件系统底层操作,第二种是通过调用shell程序实现,C语言提供了访问shell程序的接口,但shell的返回信息不便于在程序中进行分析。第三种是借助系统调用的实现。
系统调用的原理:
文件操作必须通过物理存储设备的驱动程序访问驱动器,如硬盘,光盘驱动器的驱动程序,这些驱动程序都放在Linux的内核中。Linux内核是一系列设备的驱动程序。系统调用是Linux内核提供的功能十分强大的函数。
文件操作:
打开文件open(),create(),umask是对文件权限的管理
#include <fcntl.h> //提供open函数
#include <sys/types.h>//提供mode_t类型
#include <sys/stat.h>//提供open函数的符号
#include <unistd.h>//提供close函数
文件状态和属性操作:
fstat:返回已经打开的文件的属性
lstat和stat是对未打开的文件进行操作,当文件是符号链接的时候,lstat是符号链接本身的信息,stat是该链接所指向的文件的信息。
所返回的信息都保存在struct stat中。
目录操作:
mkdir:创建目录
getcwd获得当前目录
chdir:改变当前目录
opendir:打开目录
readdir获取目录信息
closedir关闭目录流
删除目录或文件
rmdir 删除目录
unlink 删除文件
mkstemp 创建临时文件
第14章 文件I/O 操作
1. 非缓冲文件操作
非缓冲文件操作针对小规模文件的读写,或是实时设备。主要用到的函数是read()和write()。 这两个函数通过文件描述符找到文件,操作系统预先分配的3个文件描述符:
0:标准输入,1:标准输出,2:标准错误
2.缓冲文件操作
缓冲区是为程序分配的内存块,在进行数据量比较大并且不要求实时性的I/O中,一部份数据被置于缓冲区中。利用文件流结构指针FILE*作为文件的标识符,同时提供了一系列的缓冲文件操作函数。预先定义的3个文件流:
stdin:标准输入,stdout:标准输出,stderr:标准错误
第15章 进程控制
- 进程控制
在 UNIX 系统中,用户创建一个新进程的唯一方法就是调用系统调用 fork。调 用 fork 的进程称为父进程,而新创建的进程叫做子进程。系统 调用的语法格式:
pid = fork();
在从系统调用 fork 中返回时,两个进程除了返回值 pid 不同外,具有 完全一样的用户级上下文。在子进程中,pid 的值为零。在系统启动时由核心内 部地创建的进程0是唯一不通过系统调用 fork 而创建的进程。
核心为系统调用 fork 完成下列操作:
为新进程在进程表中分配一个空项。
为子进程赋一个唯一的进程标识号 (PID)。
做一个父进程上下文的逻辑副本。由于进程的某些部分,如正文区,可能被几个 进程所共享,所以核心有时只要增加某个区的引用数即可,而不是真的将该区拷贝到一个 新的内存物理区。
增加与该进程相关联的文件表和索引节点表的引用数。
对父进程返回子进程的进程号,对子进程返回零。
理解系统调用 fork 的实现是十分重要的,因为子进程就象从天而降一样地开始 它的执行序列。
第16章 进程间通信
1.几种进程间通信机制
无名管道和命名管道:管道用于有父子关系进程间的通信,命名管道用于无父子关系的进程间通信。
信号Signal:进程间高级通信机制,UNIX早期信号函数signal(),从BSD引入信号函数sigaction()
消息队列:是以POSIX和System V为标准的通信机制。
共享内存:多个进程访问同一个内存空间,适合于数据量极大和数据结构极为复杂的进程间通信。
信号量Semaphore:主要用于解决进程的同步和相关资源的抢占。
套接字Socket:是一种数据访问机制,不仅可用于进程间通信,还可用于网络间通信。最大的好处在于:Linux下的程序能快速移植到其他类UNIX平台上。
D-Bus:高级进程间通信机制
管道
pipe系统调用可以创建无名管道,open系统调用创建命名管道
int pipe(int filedes[2])//创建管道
使用write和read来读写管道。
第17章 线程控制
进程是操作系统中资源管理的最小单位,线程是程序执行的最小单位。在操作系统设计上,从进程演化出线程最主要的目的就是要更好的支持多处理器以及减少上下文切换开销。
一个进程至少需要一个线程作为它的指令执行体,进程管理着计算机资源,而将线程分配到某个CPU上执行。
进程切换导致上下文的切换,带来很大的开销。而线程无需上下文切换,因为多个线程共享同一个进程的上下文。多个线程也共享同一个进程的CPU周期,进程的状态并未因线程的切换而改变。
Linux上曾经出现多种线程标准,但所有的标准都统一于POSIX下。最广泛使用的是Pthread标准。Pthread线程与轻量级进程(LWP)相似。
用户级线程和内核级线程