ch1-1 linux basics
谈谈linux理解
linux是根据 GNU GPL 开发的免费类 Unix 操作系统。开源,受欢迎,支持大多数可用平台
创始人:Linus
发行版包括ubuntu、centos、debian、red hat等
mbr,gpt
mbr
- 在基于Intel的计算机上必须进行分区
- 最多四个主分区
- 一个主分区可以是扩展分区
- 扩展分区可以容纳无限数量的逻辑分区(Linux:最大59)
gpt
- 保留的 MBR 是为了在较老的机器上也能读取到磁盘上的信息
- GPT 是 MBR 不够用了才会选择使用
- 支持上百个主分区,不需要扩展分区(支持超过128,但是windows限制128)
- Header记录Entry信息,Entry记录Partition信息,形成三级结构
- Secondary GPT 是备份,因此 GPT 相较于 MBR 方式会有更多的空间无法使用
文件系统概念
- 操作系统中负责存取和管理文件的部分
- VFS, EXT2, EXT3, FAT32
bootloader只要求grub
- 程序存储在 MBR (第一阶段) 和 /boot/grub (第1.5和第二阶段) 中
- 了解文件系统结构;无需像LILO一样激活配置
- 配置文件:/boot/grub/grub.cfg
- 最重要就是配置内核和init文件的位置
- 通过grub-install安装在MBR中
1 |
|
编译开源软件流程
1 |
|
命令行提示符
- 可以自己配置
- 修改环境变量:
export SUDO_PS1="\u@\h:\w\$"
,export PS1="\u@\h:\w\$"
- 修改环境变量:
$
:以普通用户身份登录#
:以root身份登录
所有ppt出现的命令
- passwd:更改密码
- mkpasswd:生成随机密码
- date,cal:找出今天的日期并显示日历
- who,finger:找出还有谁在系统上处于活动状态
- clear:清除屏幕
- echo:在屏幕上写一条消息
- write、wall、talk、mesg
- write:给其他用户发信息
- wall:write all, 给所有登录到系统的用户发信息
- talk:建立聊天session
- mesg:可以屏蔽用户发来的信息
- pwd:当前目录
- cd:更改目录
- mkdir:创建目录
- rmdir:删除目录
- ls -l -i -R -a
- touch:更新文件的访问, 修改时间
- cp:复制文件
- mv:移动并重命名文件
- ln:链接文件
- rm:删除文件
- cat:打印文件内容
- more/less:逐页显示文件,more不可以回退,less可以回退
- ps:报告进程状态
- pstree:显示进程树
- jobs, fg, bg, ctrl-z:作业控制
- bg: 后台执行
- fg: 前台执行
- ctrl-z: 暂停进程, 可通过fg, bg恢复
- kill:杀死进程
- nohup:运行命令,忽略挂起信号
- nice,renice:修改进程优先级
top:查看进程的cpu占用
文件操作
- 列出目录内容: ls, (dir, vdir 与ls功能类似)
- 创建特殊文件: mkdir, mknod, mkfifo
- mknod: 创建设备文件
- mkfifo: 创建管道
- 文件操作: cp, mv, rm
- 修改文件属性: chmod, chown, chgrp, touch
- chown: 改文件拥有者、用户组
- chgrp: 更改用户组
- 查找文件: (locate), find
- locate: 功能和 find 类似
- 字符串匹配: grep(egrep)
- grep: 在文本文件中搜索字符串
- egrep: grep 扩展
- 其它: pwd, cd, ar, file, tar, more, less, head, tail, cat
- ar: 打包库文件
- file: 显示文件类型
- more, less: 一页页显示
- head, tail: 显示文件头部、尾部
- 进程操作:ps, kill, jobs, fg, bg, nice
- 其它
- who, whoami, passwd, su, uname, …
- whoami: 当前用户名
- uname: 显示内核信息
- man
- who, whoami, passwd, su, uname, …
七种文件类型必考
- 普通文件(regular file):
- 文本或代码数据;没有特别的内部结构
- 字符型设备文件(character special file)
- 块型设备文件(block special file)
- special files:代表硬件或逻辑设备
- 位于 /dev 目录
- 网络接口(socket)
- 符号链接(symbolic link)
- 软链接:类似windows上的快捷方式
- 硬链接:同一个文件有两个文件名,创建出来的硬链接不占用磁盘空间和inode号。
- 目录(directory):该目录中的文件列表
- 管道(fifo)
目录结构
/boot
:内核、bootloader的配置,包括引导加载程序相关的文件。内核的initrd、vmlinux、grub文件位于/boot下。/etc
:系统的配置文件所在地,下载软件的配置文件在也在这里,包含所有程序所需的配置文件/bin
:程序文件夹,包含二进制可执行文件,例如ls
,其实是在执行一个程序;也有一部分程序在/usr/bin
(在我的linux上,/bin是/usr/bin的软链接)/mnt
:挂载目录,临时挂载目录,系统管理员可以挂载文件系统。/sbin
:系统二进制文件,但是这个目录下的Linux命令通常由系统管理员使用,对系统进行维护,例如ifconfig/fdisk
也有部分程序在/sbin
,例如分区命令fdisk
/usr
:资源文件夹(和编程相关的);编译器、默认的头文件、系统中的库文件,包含二进制文件、库文件、文档和二级程序的源代码/usr/bin
中包含用户程序的二进制文件。/bin
/usr/sbin
中包含系统管理员的二进制文件。/sbin
/usr/lib
中包含了/usr/bin
和/usr/sbin
用到的库。/usr/local
中包含了从源安装的用户程序。
/lib
:系统库。包含支持位于/bin和/sbin下的二进制文件的库文件;库文件名为ld*或lib*.so.*
/proc
:包括系统进行相关信息。这是一个虚拟的文件系统,包含有关正在运行的进程的信息;系统资源以文本信息形式存在。/var
:系统里的可变数据,变量文件,并不是存放在磁盘上的数据,一般是存放在内存中的数据。- 系统日志文件
/var/log
- 包和数据库文件
/var/lib
- 电子邮件
/var/mail
- 打印队列
/var/spool
- 锁文件
/var/lock
- 多次重新启动需要的临时文件
/var/tmp
- 系统日志文件
/dev
:包含设备文件,这些包括终端设备、USB或连接到系统的任何设备。例如/dev/tty1
/tmp
:包含系统和用户创建的临时文件,当系统重新启动时,这个目录下的文件都将被删除。/home
:用home目录来存储他们的个人档案。/opt
:可选的附加应用程序/media
:用于挂载可移动设备的临时目录。举例来说,挂载CD-ROM的/media/cdrom,挂载软盘驱动器的/media/floppy/srv
:srv代表服务。包含服务器特定服务相关的数据。- 修改环境变量PATH,临时修改可以直接
PATH=$PATH:/bin
,但是要永久生效得修改配置文件/etc/profile
文件权限
- 三个访问级别:
- 用户(User):创建文件的用户
- 组(Group):拥有文件的组中的所有用户
- 其他(Others):其他
- 三个权限:
- 读取(r):读取文件内容或目录内容
- 写(w):更改文件内容或在目录中创建/删除文件
- 执行(x):以程序执行文件或使用目录作为活动目录
ls -l
chmod <who operator what> filename
- who:
u
= owner of fileg
= groupo
= other users on the systema
= all(u + g + o)
- operator:
+
= add permission-
= remove permission=
= clear permissions and set to mode specified
- what:
r, w, x
- who:
chmod <number> file
- Default File Permissions
类型 | 权限 | 数字权限 |
---|---|---|
File | -rw-r—r— | 644 |
Directory | drwxr-xr-x | 755 |
进程概念
- 进程是一个正在执行的程序实例。由执行程序,它的当前值,状态信息以及通过操作系统管理此进程执行情况的资源组成。
man,info
man
使用 man 命令,您可以阅读命令的手册页
手册页存储在 /usr/man
info
用于阅读文档的程序,有时可以代替手册页
有关信息的信息存储在 /usr/info
linux层次图
ch1-2 linux basics
重定向
- 标准输入、标准输出、标准错误
- 对应的文件描述符:0, 1, 2
- C语言变量:stdin, stdout, stderr
<
,>
,>>
,2>
,2>>
,&>
- 例:
kill –HUP 1234 > killout.txt 2> killerr.txt
- 例:
kill –HUP 1234 > killout.txt 2>&1
&1
: 1号fd, 不加&会重定向到名称为1的文件- 为什么需要将标准错误重定向到标准输出: 标准错误没有缓冲区,⽽stdout有
<
: 重定向 0号fd>
: 重定向内容会覆盖掉文件, 默认重定向 1号fd>>
: 重定向内容追加到文件末尾, 默认重定向 1号fd2>
: 只重定向 2号fd 的内容&>
: 重定向 1,2号fd
- 例:
管道
- 一个进程的输出作为另一个进程的输入
- 存在一个管道文件,这个文件作为输入传递给后面的命令
- 例:
ls | wc –l
ls –lF | grep ^d
ar t /usr/lib/libc.a | grep printf | pr -4 -t
环境变量
- 环境变量
- 操作环境的参数
- 查看和设置环境变量:echo, env, set
- env: 显示所有环境变量
- set: 设置环境变量
- 例: PATH环境变量
echo $PATH
/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/song/bin
PATH=$PATH:.
export PATH
正则表达式
可能会出道简单题
ch2 shell programming
只考bash,知道有其他shell就行
三种执行脚本方法
方法一:
1 |
|
方法二:
1 |
|
方法三:
1 |
|
方法一二原理相同:新启bash进程执行脚本
方法三使用当前bash进程执行脚本
read命令
1 |
|
引号的用法
用户变量、环境变量,参数变量
环境变量
$HOME
: 当前用户的登陆目录$PATH
: 以冒号分隔的用来搜索命令的目录清单$PS1
:命令行提示符,通常是 “$” 字符$PS2
:辅助提示符,用来提示后续输入,通常是 “>” 字符$IFS
:输入区分隔符。当 shell 读取输入数据时会把一组字符看成是单词之间的分隔符,通常是空格、制表符、换行符等。
参数变量和内部变量
$#
: 传递到脚本程序的参数个数$0
: 脚本程序的名字$1,$2,..
: 脚本程序的参数$*
: 一个全体参数组成的清单,它是一个独立的变量,各个参数之间用环境变量IFS中的第一个字符分隔开$@
: “$*”的一种变体,它不使用IFS环境变量。
字符串比较
算数比较
文件
逻辑
if语句
1 |
|
- 紧凑模式:使用 ; 分割
1 |
|
case语句
- 双分号
1 |
|
1 |
|
for
- 适用于对一系列字符串循环处理
1 |
|
1 |
|
while
1 |
|
1 |
|
1 |
|
$(())整数运算,否则会看作字符串
不推荐使用 until
select
1 |
|
命令表
命令组合
分号串联:command1 ; command2 ; …
&&: 前面成功才会执行后面的命令
||: 前面失败才会执行, 可用作备用命令
{statement1; statement2 ; … ;} 会看做一个命令
…….都看了吧
函数
定义时不带参数
1 |
|
- 局部变量: local关键字
- 函数的调用: func para1 para2 …
- 返回值: return
例子
其他
杂项命令
- break: 从for/while/until循环退出
- continue: 跳到下一个循环继续执行
- exit n: 以退出码”n”退出脚本运行
- return: 函数返回
- export: 将变量导出到shell,使之成为shell的环境变量
- set: 为shell设置参数变量
- unset: 从环境中删除变量或函数
- trap: 指定在收到操作系统信号后执行的动作
- “:”(冒号命令): 空命令
- “.”(句点命令)或source: 在当前shell中执行命令
捕获命令输出
$(command) 或 `command`
$PWD 与 $(pwd)
参数扩展
即时文档
- 输入 !CATINPUT! 才会停止
1 |
|
ch3 Programming Prerequisite
知道什么是elf
- “ELF” 是 “Executable and Linkable Format” 的缩写,是一种二进制文件格式,用于可执行文件、目标文件和库文件
- 它是一种标准的二进制文件格式,可用于 Linux 操作系统下的可执行程序
程序设计语言是解释型还是编译型,什么意思
编译型语言是指在程序运行之前,需要先将源代码编译成机器码,然后再运行机器码。
解释型语言则是在程序运行时,逐行解释源代码并执行。
静态库与动态库联系和区别
静态库和动态库都是程序开发中常用的库文件。
静态库在链接时会完整地拷贝至可执行文件中,被多个依赖多次使用就会有多份冗余拷贝。
动态库则在链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存
静态库的扩展名一般为“.a”或“.lib”,而动态库的扩展名一般为“.so”或“.dll”。
java编译过程
Java文件从源文件创建到程序运行要经过两大步骤:
- 源文件由编译器编译成字节码(ByteCode)
- 字节码由Java虚拟机解释运行
gcc参数
- -E: 只对源程序进行预处理(调用cpp预处理器)
- -S: 只对源程序进行预处理、编译
- -c: 执行预处理、编译、汇编而不链接
- -o output_file: 指定输出文件名
- -g: 产生调试工具必需的符号信息
- -O/On: 在程序编译、链接过程中进行优化处理
- -Wall: 显示所有的警告信息
- -Idir: 指定额外的头文件搜索路径
- -Ldir: 指定额外的库文件搜索路径
- -lname: 链接时搜索指定的库文件
- -DMACRO[=DEFN]: 定义MACRO宏
扩展名
.h 头文件
.s 汇编
.o 目标文件
.a 静态库
.so 动态库
gdb(正常不考) 功能,原理
- 设置断点
- 监视变量值
- 单步执行
- 修改变量值
makefile掌握ppt涉及内容
https://blog.csdn.net/weixin_38391755/article/details/80380786
- 预定义变量可以看
- 不考复杂的、函数等
1 |
|
ch3-1 Linux System Programming – File System
什么是文件、文件系统
文件:可以写入、读取或两者兼有的对象,文件具有某些属性,包括访问权限和类型
文件系统:操作系统中负责存取和管理文件的部分,是文件及其属性的集合,为引用文件的文件序列号提供了名称空间。
文件系统三层含义
- 一种特定的文件格式,例如EXT2, FAT16, FAT32
- 指按指定格式进行”格式化”的一块存储介质
- 指操作系统中(通常内核中)用来管理文件系统以及对文件进行操作的机制及其实现
VFS
采⽤标准的Unix系统调⽤读写位于不同物理介质上的不同⽂件系统,使得open()等系统调⽤不⽤关⼼底层的存储介质和⽂件类型
- 超级块(super block):某一个磁盘的某一个分区的文件系统的信息,记录了文件系统类型和参数。
- i-node 对象(i-node object 索引节点):
- 记录真正的文件,文件存储在磁盘上时是按照索引号访问文件的
- 文件对象(file object):记录了文件描述符、索引号,不对应真正的文件,文件打开会创建出文件对象,文件关闭才会释放内核中的文件对象。记录了文件的读写状态。
- 目录项对象(dentry object):在路径上,无论是目录还是文件,都是一个dentry对象对应到目录包含的i-node上,目录项包括索引节点编号,目录项名称长度以及名称。
硬链接软链接 重点
- 硬链接
- 不同的文件名对应同一个inode
- 不能跨越文件系统
- 对应系统调用link
- 命令行使用 ln [文件名] [文件名]
- 应用程序使用 int link(const char oldpath, const char newpath);
- 软链接
- 存储被链接文件的文件名(而不是inode)实现链接
- 可以跨越文件系统
- 对应系统调用symlink
- 命令行使用 ln -s [文件名] [文件名]
- 应用程序使用 int symlink(const char oldpath, const char newpath);
系统调用和c库的关系 重点
看清题目要求,要求系统调用还是c库
系统调用部分:
int open(const char *pathname, int flags, mode_t mode);
- flags
- O_RDONLY:只读
- O_WRONLY:只写
- O_RDWR:读写
- O_APPEND:追加模式打开
- O_TRUNC:覆盖模式
- O_CREAT:文件不存在则创建
- O_EXCL:和O_CREAT同时使用,存在时出错
- flags
int close(int fd);
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
off_t lseek(int fd, off_t offset, int whence);
- 用于设置文件读写指针的位置
- whence: 起始位置
- SEEK_SET:从头偏移offset
- SEEK_CUR:从当前偏移offset
- SEEK_END:从尾偏移offset
int dup(int oldfd);
int dup2(int oldfd, int newfd);
- dup2 可以指定新的fd,通常用于重定向
int fcntl(int fd, int cmd, struct flock *lock);
cmd
- F_DUPFD:复制文件描述符
- F_GETFD/F_SETFD:获取/设置文件描述符标志,为解决fork子进程执行其他任务(exec等)导致父进程的文件描述符被复制到子进程中,使得对应文件描述符无法被之后需要的进程获取。设置了这个标记后可以使得子进程在执行exce等命令后释放对应的文件描述符资源。
- F_GETFL/F_SETFL:获得/设置文件状态标志(open/creat中的flags 参数)
- F_GETOWN/F_SETOWN: 管理 I/O 可用相关的信号。
- F_GETLK:获得文件的锁信息
- F_SETLK:设置文件锁,如果无法获取锁,则返回错误信息
- F_SETLKW:设置文件锁,如果无法获取锁,则等待直到可以获取为止
文件锁部分要掌握
1 |
|
fcntl(fd, F_SETFD, 1);
这里将close-on-exec flag设置为true,所以调用execl的时候,fd会关闭。最后的执行结果:test.txt文件中只会有”ooooo”,不会有”zzzzz”
int stat(const char *filename, struct stat *buf);
- 获取文件状态信息
- 结果写入 buf
int fstat(int fd, struct stat *buf);
- 用于获取已打开文件的状态信息
int lstat(const char *path, struct stat *buf);
- lstat函数类似于stat函数,但是对于符号链接文件,它返回符号链接本身的状态信息,而不是链接所指向的文件的状态信息
库函数部分
- 会自动处理缓存
FILE *fopen(const char *filename, const char *mode); int fclose(FILE *stream);
- r 读
- w 清空写
- a 追加
- r+ 读写
- w+ 清空读写
- a+ 不清空读写
int fclose(FILE *fp);
输入一个字符
int getc(FILE *fp)
:是预定义宏,无函数副作用,更快int fgetc(FILE *fp)
:常用,在用到函数副作用/函数指针用
输出一个字符到文件
int putc(int c, FILE *fp)
int fputc(int c, FILE *fp)
输入字符串
char *fgets(char *s, int size, FILE *stream);
- 常用,最多从流中读取并存储size-1个字符,并最后添加一个\0
输出字符串
int fputs(const char *s, FILE *stream);
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
- 参数分别为 缓冲区指针,数据块大小,数据块数量,文件指针
size fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
int scanf(const char *format, ...);
int printf(const char *format, ...);
int fseek(FILE *stream, long int offset, int whence);
- 用于移动文件内部的位置指针
- whence
- SEEK_SET:从文件开头开始偏移。
- SEEK_CUR:从当前位置开始偏移。
- SEEK_END:从文件结尾开始偏移。
long ftell(FILE *stream);
- 获取文件内部的位置指针相对于文件开头的偏移量
void rewind(FILE *stream);
- 将文件内部的位置指针重新指向文件开头
int fflush(FILE *stream);
- 刷新文件流。把流里的数据立刻写入文件
umask
权限、链接系统调用是重点
来自 new bing
- SUID(Set User ID):当一个可执行文件被设置了SUID权限后,它在执行时就会具有该文件所有者的权限。例如,如果一个文件的所有者是root,那么当一个普通用户执行该文件时,该文件就会以root的身份运行。SUID权限可以让普通用户执行一些只有root才能执行的任务。
- SGID(Set Group ID):当一个目录被设置了SGID权限后,该目录下新建的文件和子目录都会继承该目录的组ID。例如,如果一个目录的组ID是staff,那么在该目录下新建的文件和子目录都会属于staff组。SGID权限可以让多个用户共享同一个组。
- Sticky bit:当一个目录被设置了Sticky bit权限后,只有该目录的所有者和root用户才能删除该目录下的文件。例如,/tmp目录就被设置了Sticky bit权限,这样其他用户就不能删除/tmp目录下的文件。
系统调用
int chmod(const char *path, mode_t mode);
int fchmod(int fildes, mode_t mode);
int chown(const char *path, uid_t owner, gid_t group);
int fchown(int fd, uid_t owner, gid_t group);
int lchown(const char *path, uid_t owner, gid_t group);
mode_t umask(mode_t mask);
- 为进程设置文件存取权限屏蔽字,并返回以前的值
目录操作
int mkdir(const char *pathname, mode_t mode);
int rmdir(const char *pathname);
int chdir(const char *path);
int fchdir(int fd);
char *getcwd(char *buf, size_t size);
- 获得当前工作目录的绝对路径
文件锁 重点
- 记录锁:按记录加锁
- 劝告锁:
- 检查,加锁由应用程序自己控制
- 不会强制应用程序不允许访问,只是提醒
- 强制锁
- 检查,加锁由内核控制
- 影响 open() read() write()
- 共享锁:可以读
- 排他锁:读写均不可
fcntl
int fcntl(int fd, int cmd, struct flock *lock);
- cmd
- F_GETLK:获得文件的封锁信息
- F_SETLK:对文件的某个区域封锁或解除封锁
- F_SETLKW:功能同F_SETLK, wait方式。
- cmd
ch4 内核
内核概念
操作系统是一系列程序的集合,其中最重要的部分构成了内核
单内核/微内核
- 单内核是一个很大的进程,内部可以分为若干模块,运行时是一个独立的二进制文件,模块间通讯通过直接调用函数实现
- 微内核中大部分内核作为独立的进程在特权下运行,通过消息传递进行通信
- Linux内核的能力:内存管理,文件系统,进程管理,多线程支持,多处理支持,抢占式。
- Linux内核区别于其他UNIX商业内核的优点
- 单内核,模块支持
- 免费/开源
- 支持多种CPU,硬件支持能力非常强大
- Linux开发者都是非常出色的程序员
- 通过学习Linux内核的源码可以了解现代操作系统的实现原理
层次结构
驱动与模块 重点
- 形式为 .ko,
模块.ko
insmod <module.ko> [module parameters]
- 加载模块
rmmod
lsmod
- 列出内核中的模块
modprobe [-r] <module.name>
- 载入指定模块及其依赖模块
- -r 卸载模块
modinfo
- 显示模块信息
depmod
- 用于生成modules.dep文件,该文件记录了所有模块之间的依赖关系
模块依赖
- 一个模块A引用另一个模块B所导出的符号,我们就说模块B被模块A引用。
- 如果要装载模块A,必须先要装载模块B。否则,模块B所导出的那些符号的引用就不可能被链接到模块A中。这种模块间的相互关系就叫做模块依赖。
模块之间的通讯
- 模块是为了完成某种特定任务而设计的。其功能比较的单一,为了丰富系统的功能,所以模块之间常常进行通信。其之间可以共享变量,数据结构,也可以调用对方提供的功能函数。
应用程序与内核的区别
加上注意点一共9点,写出4点即可
c语言程序 | 内核模块 |
---|---|
运行在用户空间 | 运行在内核空间 |
入口为 main() | 入口由 module_init() 指定 |
没有出口 | 出口由 module_exit() 指定 |
直接运行 | 通过 insmod |
通过 gdb 调试 | 通过 kdbug,kdb,kgdb等 调试 |
- 不能使用 c 库开发驱动程序
- 没有内存保护机制
- 小内核栈
- 并发上的考虑
华为 15分
openEuler 是一款通用服务器操作系统;
支持 x86 和 ARM 等多种处理器架构;
2019年底开源,成为openEuler
鲲鹏处理器:基于ARMv8-64指令集开发的通用处理器,openEuler对 鲲鹏处理器 做了增强,没有神经网络加速
openEuler优化鲲鹏的4个方面
多核调度技术:Numa aware
软硬件协同:KAE
智能优化引擎:A-Tune
轻量级虚拟化:提供 iSulad 轻量级容器全场景解决方案
openEuler使用多队列调度策略
openEuler 通信支持共享内存与消息传递
openEuler 内存管理有预测机制,不是100%准确
openEuler大量使用寄存器,使用精简指令集 risc
编程题
使用C的库函数,编写一个函数void bindiff(char file1,char file2,char *fileo),将文件从file1、file2对应的路径中读取并逐字节比对,将相同的字节输出到fileo对应的文件中。(25分)
1 |
|
shell获得用户输入的100个整数,并输出其最大值,最小值,总和。
1 |
|
用系统调用实现一个copy.cpp模块,输入两个参数(原文件名,目标文件名),将原文件中的内容复制到目标文件中。并且编写Makefile编译链接上述模块。
1 |
|
1 |
|
使用系统调用实现函数half(a, b)将a文件的一半拷贝到b文件,且b仅包含a文件的后一半的内容
1 |
|