书签 分享 收藏 举报 版权申诉 / 40
上传文档赚钱

类型达内Unix编程.doc

  • 上传人(卖家):无敌的果实
  • 文档编号:305605
  • 上传时间:2020-02-26
  • 格式:DOC
  • 页数:40
  • 大小:175.50KB
  • 【下载声明】
    1. 本站全部试题类文档,若标题没写含答案,则无答案;标题注明含答案的文档,主观题也可能无答案。请谨慎下单,一旦售出,不予退换。
    2. 本站全部PPT文档均不含视频和音频,PPT中出现的音频或视频标识(或文字)仅表示流程,实际无音频或视频文件。请谨慎下单,一旦售出,不予退换。
    3. 本页资料《达内Unix编程.doc》由用户(无敌的果实)主动上传,其收益全归该用户。163文库仅提供信息存储空间,仅对该用户上传内容的表现方式做保护处理,对上传内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知163文库(点击联系客服),我们立即给予删除!
    4. 请根据预览情况,自愿下载本文。本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
    5. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007及以上版本和PDF阅读器,压缩文件请下载最新的WinRAR软件解压。
    配套讲稿:

    如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。

    特殊限制:

    部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。

    关 键  词:
    Unix 编程
    资源描述:

    1、Unix环境编译讲稿Version 1.0Unix Kernel Programming达内IT培训集团加拿大达内集团研发二部 修订历史摘要日期修改原因版本文档创建2009-4-18新建1.0目录1.Unix系统函数53.1.内存管理53.1.1.内存管理在语言结构上的变化53.1.2.Unix/Linux内存管理53.1.3. 物理内存和虚拟内存53.1.4. C 风格的内存分配程序63.1.5.Unix/Linux的基本内存分配程序63.2.Linux标准IO93.3.目录管理293.4.系统信息353.5.时间与日期381.Unix系统函数3.1.内存管理3.1.1.内存管理在语言结构上

    2、的变化C/C+语言的内存管理如下阶段变化 1. 从malloc/free到new/delete.这场变革是OOP技术兴起的产物。C+是强类型语言,new/delete的主要成果也就是加强了类型观念,减少了强制类型转换的需求。但是从内存管理角度看,这个变革并没有多少的突破性。 2. 从new/delete到内存配置器(allocator)。自从STL被纳入C+标准库后,C+世界产生了巨大的变化。而从内存管理角度来看,allocator的引入也是C+内存管理一个突破。留意一下你就可以发现,整个STL所有组件的内存均从allocator分配。也就是说,STL并不推荐使用new/delete进行内存管

    3、理,而是推荐使用allocator.3.1.2.Unix/Linux内存管理Unix/Linux低层采用三层结构,实际使用中可以方便映射到两层或者三层结构,以适用不同的硬件结构。最下层的申请内存函数get_free_page。之上有三种类型的内存分配函数1.kmalloc类型。内核进程使用,基于切片(slab)技术,用于管理小于内存页的内存申请。思想出发点和应用层面的内存缓冲池同出一辙。但它针对内核结构,特别处理,应用场景固定,不考虑释放。2.vmalloc类型。内核进程使用。用于申请不连续内存。3.brk/mmap类型。用户进程使用。malloc/free实现的基础。3.1.3. 物理内存和

    4、虚拟内存要理解内存在程序中是如何分配的,首先需要理解如何将内存从操作系统分配给程序。计算机上的每一个进程都认为自己可以访问所有的物理内存。显然,由于同时在运行多个程序,所以每个进程不可能拥有全部内存。实际上,这些进程使用的是虚拟内存。只是作为一个例子,让我们假定您的程序正在访问地址为 629 的内存。不过,虚拟内存系统不需要将其存储在位置为 629 的 RAM 中。实际上,它甚至可以不在 RAM 中 如果物理 RAM 已经满了,它甚至可能已经被转移到硬盘上!由于这类地址不必反映内存所在的物理位置,所以它们被称为虚拟内存。操作系统维持着一个虚拟地址到物理地址的转换的表,以便计算机硬件可以正确地响

    5、应地址请求。并且,如果地址在硬盘上而不是在 RAM 中,那么操作系统将暂时停止您的进程,将其他内存转存到硬盘中,从硬盘上加载被请求的内存,然后再重新启动您的进程。这样,每个进程都获得了自己可以使用的地址空间,可以访问比您物理上安装的内存更多的内存。在 32-位 x86 系统上,每一个进程可以访问 4 GB 内存。现在,大部分人的系统上并没有 4 GB 内存,即使您将 swap 也算上, 每个进程所使用的内存也肯定少于 4 GB。因此,当加载一个进程时,它会得到一个取决于某个称为 系统中断点(system break)的特定地址的初始内存分配。该地址之后是未被映射的内存 用于在 RAM 或者硬盘

    6、中没有分配相应物理位置的内存。因此,如果一个进程运行超出了它初始分配的内存,那么它必须请求操作系统“映射进来(map in)”更多的内存。(当内存的虚拟地址有一个对应的物理地址来存储内存内容时,该内存将被映射。)3.1.4. C 风格的内存分配程序C 编程语言提供了两个主要的函数: 1. malloc:该函数分配给定的字节数,并返回一个指向它们的指针。如果没有足够的可用内存,那么它返回一个空指针。 2.free:该函数获得指向由 malloc 分配的内存片段的指针,并将其释放,以便以后的程序或操作系统使用。其他还有两个函数:calloc与realloc函数,依赖上面两个函数。函数说明:#inc

    7、lude void *calloc(size_t nmemb, size_t size);void *malloc(size_t size);void free(void *ptr);void *realloc(void *ptr, size_t size);示例代码:略3.1.5.Unix/Linux的基本内存分配程序基于 UNIX 的系统有两个可映射到附加内存中的基本系统调用: 1.brk: brk() 是一个非常简单的系统调用。得到一个系统中断点,该位置是进程映射的内存边界。 brk() 只是简单地将这个位置向前或者向后移动,就可以向进程添加内存或者从进程取走内存。 2.mmap: mm

    8、ap(),或者说是“内存映像”,类似于 brk(),但是更为灵活。首先,它可以映射任何位置的内存,而不单单只局限于进程。其次,它不仅可以将虚拟地址映射到物理的 RAM 或者 swap,它还可以将它们映射到文件和文件位置,这样,读写内存将对文件中的数据进行读写。不过,在这里,我们只关心 mmap 向进程添加被映射的内存的能力。 munmap() 所做的事情与 mmap() 相反。brk() 或者 mmap() 都可以用来向我们的进程添加额外的虚拟内存。brk函数说明:#include int brk(void *end_data_segment); void *sbrk(intptr_t inc

    9、rement);int brk(void *eds); brk动态地改变数据段所用的内存数量,这种改变是通过重置程序的截断值来完成的,所谓的截断值是数据段结尾以上的第一个位置的地址。分配的内存空间水截断值增加而增加,如果成功,数据段结尾是eds,返回0,否则返回-1,全局变量error 置为ENOMEM void *sbrk(int amount); 在以分配的数据段中增加或减少amount字节数内存,代码示例:利用brk函数,实现与malloc相同的功能:#include #include void* myalloc(int bytes)void * addr_start=sbrk(0);

    10、printf(%xn,addr_start);int re=brk(addr_start+bytes);printf(%xn,sbrk(0);return addr_start;int main()void* p=myalloc(20);int* pi=(int*)p;int i=0;for(i=i;i=5;i+)*pi=i;pi+;printf(%xn,pi);sleep(200);return 0;Mmap函数说明:#include void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offse

    11、t); int munmap(void *start, size_t length);参数start:指向欲映射的内存起始地址,通常设为 NULL,代表让系统自动选定地址,映射成功后返回该地址。参数length:代表将文件中多大的部分映射到内存。参数prot:映射区域的保护方式。可以为以下几种方式的组合:1.PROT_EXEC 映射区域可被执行2.PROT_READ 映射区域可被读取3.PROT_WRITE 映射区域可被写入4.PROT_NONE 映射区域不能存取参数flags:影响映射区域的各种特性。在调用mmap()时必须要指定MAP_SHARED 或MAP_PRIVATE。1.MAP_F

    12、IXED 如果参数start所指的地址无法成功建立映射时,则放弃映射,不对地址做修正。通常不鼓励用此旗标。2.MAP_SHARED对映射区域的写入数据会复制回文件内,而且允许其他映射该文件的进程共享。3.MAP_PRIVATE 对映射区域的写入操作会产生一个映射文件的复制,即私人的“写入时复制”(copy on write)对此区域作的任何修改都不会写回原来的文件内容。4.MAP_ANONYMOUS建立匿名映射。此时会忽略参数fd,不涉及文件,而且映射区域无法和其他进程共享。5.MAP_DENYWRITE只允许对映射区域的写入操作,其他对文件直接写入的操作将会被拒绝。6.MAP_LOCKED

    13、将映射区域锁定住,这表示该区域不会被置换(swap)。参数fd:要映射到内存中的文件描述符。如果使用匿名内存映射时,即flags中设置了MAP_ANONYMOUS,fd设为-1。有些系统不支持匿名内存映射,则可以使用fopen打开/dev/zero文件,然后对该文件进行映射,可以同样达到匿名内存映射的效果。参数offset:文件映射的偏移量,通常设置为0,代表从文件最前方开始对应,offset必须是分页大小的整数倍。返回值:若映射成功则返回映射区的内存起始地址,否则返回MAP_FAILED(1),错误原因存于errno 中。错误代码:1.EBADF 参数fd 不是有效的文件描述词2.EACCE

    14、S 存取权限有误。如果是MAP_PRIVATE 情况下文件必须可读,使用MAP_SHARED则要有PROT_WRITE以及该文件要能写入。3.EINVAL 参数start、length 或offset有一个不合法。4.EAGAIN 文件被锁住,或是有太多内存被锁住。5.ENOMEM 内存不足。代码示例:#include #include #include #include #include #include #include #include #include int main()/*内存映射*/*分配4字节匿名内存空间*/int * p=mmap(0,4,PROT_READ|PROT_WRI

    15、TE,MAP_PRIVATE|MAP_ANONYMOUS,0,0);/*请改变上面的保护设置试试程序的限制*/if(errno)printf(%sn,strerror(errno);*p=20;printf(%dn,*p);/*int *q;*q=30;*/return 0;3.2.Linux标准IO3.2.1.IO基本方法open,write,read函数说明:openSYNOPSIS #include #include #include int open(const char *pathname, int flags); int open(const char *pathname, int

    16、 flags, mode_t mode); int creat(const char *pathname, mode_t mode);open 函数用于打开和创建文件。对于 open 函数来说,第三个参数(.)仅当创建新文件时才使用,用于指定文件的访问权限位(access permission bits)。pathname 是待打开/创建文件的路径名(如 C:/cpp/a.cpp);oflag 用于指定文件的打开/创建模式,这个参数可由以下常量(定义于 fcntl.h)通过逻辑或构成。 1.O_RDONLY 只读模式 2.O_WRONLY 只写模式 3.O_RDWR 读写模式打开/创建文件时,

    17、至少得使用上述三个常量中的一个。以下常量是选用的: 1.O_APPEND 每次写操作都写入文件的末尾 2.O_CREAT 如果指定文件不存在,则创建这个文件 3.O_EXCL 如果要创建的文件已存在,则返回 -1,并且修改 errno 的值 4.O_TRUNC 如果文件存在,并且以只写/读写方式打开,则清空文件全部内容 5.O_NOCTTY 如果路径名指向终端设备,不要把这个设备用作控制终端。 6.O_NONBLOCK 如果路径名指向 FIFO/块文件/字符文件,则把文件的打开和后继 I/O设置为非阻塞模式(nonblocking mode)以下三个常量同样是选用的,它们用于同步输入输出 1.

    18、O_DSYNC 等待物理 I/O 结束后再 write。在不影响读取新写入的数据的 前提下,不等待文件属性更新。 2.O_RSYNC read 等待所有写入同一区域的写操作完成后再进行 3.O_SYNC 等待物理 I/O 结束后再 write,包括更新文件属性的 I/Oopen 返回的文件描述符一定是最小的未被使用的描述符。函数说明:write#include ssize_t write(int filedes, const void *buf, size_t nbytes); 返回值:写入文件的字节数(成功);-1(出错)write 函数向 filedes 中写入 nbytes 字节数据,数

    19、据来源为 buf 。返回值一般总是等于 nbytes,否则就是出错了。常见的出错原因是磁盘空间满了或者超过了文件大小限制。函数说明:read#include ssize_t read(int filedes, void *buf, size_t nbytes); 返回值:读取到的字节数;0(读到 EOF);-1(出错) read 函数从 filedes 指定的已打开文件中读取 nbytes 字节到 buf 中。以下几种情况会导致读取到的字节数小于 nbytes : A. 读取普通文件时,读到文件末尾还不够 nbytes 字节。例如:如果文件只有 30 字节,而我们想读取 100 字节,那么实际

    20、读到的只有 30 字节,read 函数返回 30 。此时再使用 read 函数作用于这个文件会导致 read 返回 0 。 B. 从终端设备(terminal device)读取时,一般情况下每次只能读取一行。 C. 从网络读取时,网络缓存可能导致读取的字节数小于 nbytes 字节。 D. 读取 pipe 或者 FIFO 时,pipe 或 FIFO 里的字节数可能小于 nbytes 。 E. 从面向记录(record-oriented)的设备读取时,某些面向记录的设备(如磁带)每次最多只能返回一个记录。 F. 在读取了部分数据时被信号中断。示例代码:简单示例:注意其中0,1,2三个标准IO设

    21、备的使用。#include #include #include #include #include #include #include int main(int argc,char*argv,char*env)int fd=-1;/文件描述符号.char* file=./tmp.dat;/文件名int flags=O_WRONLY|O_CREAT|O_TRUNC;int mode=S_IWUSR|S_IRUSR;fd=open(file,flags,mode);if(errno!=0)perror(文件打开错误);close(fd);exit(0);/写数据到文件.char ch255; in

    22、t num=0;do/memset(ch,0,sizeof(ch);num=read(0,ch,sizeof(ch);num=write(fd,ch,num);num=write(1,ch,num);if(errno!=0)perror(文件写数据错误);close(fd);exit(0);while(strncmp(ch,exit,4)!=0);close(fd);return 0; 写基本数据:#include #include #include #include #include #include #include int main(int argc,char*argv,char*env

    23、)int fd=-1;/文件描述符号.char* file=./tmp.dat;/文件名int flags=O_WRONLY|O_CREAT|O_TRUNC;int mode=S_IWUSR|S_IRUSR;fd=open(file,flags,mode);if(errno!=0)perror(文件打开错误);close(fd);exit(0);/*写二进制数据到文件.*/*要写入的两条数据 no name score sex1 tom 98.34 f */ int no=1;char* name=malloc(60);memset(name,0,60);strcpy(name,tom);do

    24、uble score=98.34;char sex=f; int num=0;num=write(fd,&no,sizeof(no);num=write(fd,name,60);num=write(fd,&score,sizeof(score);num=write(fd,&sex,sizeof(sex);no=2;memset(name,0,60);strcpy(name,杨强);score=100.01;sex=m;num=write(fd,&no,sizeof(no);num=write(fd,name,60);num=write(fd,&score,sizeof(score);num=w

    25、rite(fd,&sex,sizeof(sex);close(fd);return 0;写结构数据类型:#include #include #include #include #include #include #include typedef structint no;char name60;double score;char sex;stu; int main()int fd=-1;/文件描述符号.char* file=./tmp.dat;/文件名int flags=O_WRONLY|O_CREAT|O_TRUNC;int mode=S_IWUSR|S_IRUSR;fd=open(file

    26、,flags,mode);if(errno!=0)perror(文件打开错误);close(fd);exit(0);stu s;s.no=1;strcpy(s.name,超人);s.score=1000;s.sex=f;write(fd,&s,sizeof(stu);s.no=2;strcpy(s.name,奥巴马);s.score=99;s.sex=m;write(fd,&s,sizeof(stu);close(fd);return 0;读取基本类型数据:#include #include #include #include #include #include #include int ma

    27、in(int argc,char*argv,char*env)int fd=-1;/文件描述符号.char* file=./tmp.dat;/文件名int flags=O_RDONLY;int mode=S_IWUSR|S_IRUSR;fd=open(file,flags,mode);if(errno!=0)perror(文件打开错误);close(fd);exit(0);/*写二进制数据到文件.*/*要写入的两条数据 no name score sex1 tom 98.34 f */int no=0;char name60;double score=0.0;char sex=0; ssize

    28、_t num=0;while(1)num=read(fd,&no,sizeof(no);/*num=0表示读取到文件末尾*/if(num=0)break;num=read(fd,name,sizeof(name);num=read(fd,&score,sizeof(score);num=read(fd,&sex,sizeof(sex);printf(%dt%st%ft%cn,no,name,score,sex);close(fd);return 0;读取结构数据类型:#include #include #include #include #include #include #include t

    29、ypedef structint no;char name60;double score;char sex; stu;int main()int fd=-1;/文件描述符号.char* file=./tmp.dat;/文件名int flags=O_RDONLY;int mode=S_IWUSR|S_IRUSR;fd=open(file,flags,mode);if(errno!=0)perror(文件打开错误);close(fd);exit(0);stu *s; s=malloc(sizeof(stu)*2); ssize_t num=0;/*读取两条记录*/num=read(fd,s,siz

    30、eof(stu)*2);/*num=0表示读取到文件末尾*/stu *pread=s;int i=0;for(;ino,pread-name,pread-score,pread-sex);pread+;free(s);close(fd);return 0;使用内存读取:#include #include #include #include #include #include #include int main(int argc,char*argv,char*env)int fd=-1;/文件描述符号.char* file=./tmp.dat;/文件名int flags=O_RDONLY;int

    31、 mode=S_IWUSR|S_IRUSR;fd=open(file,flags,mode);if(errno!=0)perror(文件打开错误);close(fd);exit(0);int len=sizeof(int)+60+sizeof(double)+sizeof(char);char *item=malloc(len); ssize_t num=0;while(1)num=read(fd,item,len);/*num=0表示读取到文件末尾*/if(num=0)break;printf(%dt,*(int*)item);item+=sizeof(int);printf(%st,(ch

    32、ar*)item);item+=60;printf(%ft,*(double*)item);item+=sizeof(double);printf(%ctn,*item);close(fd);return 0;3.2.2.文件状态与截取stat、truncate函数说明:stat #include #include #include int stat(const char *path, struct stat *buf); int fstat(int filedes, struct stat *buf); int lstat(const char *path, struct stat *buf

    33、);int stat(const char *restrict pathname, struct stat *restrict buf);提供文件名字,获取文件对应属性。int fstat(int filedes, struct stat *buf);通过文件描述符获取文件对应的属性。int lstat(const char *restrict pathname, struct stat *restrict buf);连接文件描述命,获取文件属性。struct stat mode_t st_mode; /文件对应的模式,文件,目录等 ino_t st_ino; /inode节点号 dev_t

    34、st_dev; /设备号码 dev_t st_rdev; /特殊设备号码 nlink_t st_nlink; /文件的连接数 uid_t st_uid; /文件所有者 gid_t st_gid; /文件所有者对应的组 off_t st_size; /普通文件,对应的文件字节数 time_t st_atime; /文件最后被访问的时间 time_t st_mtime; /文件内容最后被修改的时间 time_t st_ctime; /文件状态改变时间 blksize_t st_blksize; /文件内容对应的块大小 blkcnt_t st_blocks; /伟建内容对应的块数量 ;st_mode

    35、 则定义了下列数种情况:S_IFMT 0170000 文件类型的位遮罩S_IFSOCK 0140000 scoketS_IFLNK 0120000 符号连接S_IFREG 0100000 一般文件S_IFBLK 0060000 区块装置S_IFDIR 0040000 目录S_IFCHR 0020000 字符装置S_IFIFO 0010000 先进先出S_ISUID 04000 文件的(set user-id on execution)位S_ISGID 02000 文件的(set group-id on execution)位S_ISVTX 01000 文件的sticky位S_IRUSR(S_I

    36、READ) 00400 文件所有者具可读取权限S_IWUSR(S_IWRITE)00200 文件所有者具可写入权限S_IXUSR(S_IEXEC) 00100 文件所有者具可执行权限S_IRGRP 00040 用户组具可读取权限S_IWGRP 00020 用户组具可写入权限S_IXGRP 00010 用户组具可执行权限S_IROTH 00004 其他用户具可读取权限S_IWOTH 00002 其他用户具可写入权限S_IXOTH 00001 其他用户具可执行权限上述的文件类型在POSIX 中定义了检查这些类型的宏定义:S_ISLNK (st_mode) 判断是否为符号连接S_ISREG (st_

    37、mode) 是否为一般文件S_ISDIR (st_mode)是否为目录S_ISCHR (st_mode)是否为字符装置文件S_ISBLK (s3e) 是否为先进先出S_ISSOCK (st_mode) 是否为socket返回值:执行成功则返回0,失败返回-1,错误代码存于errno错误代码:ENOENT 参数file_name指定的文件不存在ENOTDIR 路径中的目录存在但却非真正的目录ELOOP 欲打开的文件有过多符号连接问题,上限为16符号连接EFAULT 参数buf为无效指针,指向无法存在的内存空间EACCESS 存取文件时被拒绝ENOMEM 核心内存不足ENAMETOOLONG 参数

    38、file_name的路径名称太长函数说明:truncate #include #include int truncate(const char *path, off_t length); int ftruncate(int fd, off_t length);函数说明:truncate()会将参数path指定的文件大小改为参数length指定的大小。 如果原来的文件大小比参数length大,则超过的部分会被删除返回值:执行成功则返回0, 失败返回-1, 错误原因存于errno错误代码:EACCESS参数path所指定的文件无法存取EROFS欲写入的文件存在于只读文件系统内EFAULT参数path指针超出可存取空间EINVAL参数path包含不合法字符ENAMETOOLONG参数path太长ENOTDIR参数path路径并非一目录EISDIR参数path指向一目录ETXTBUSY参数path所指的文件为共享程序,而且正被执行中ELOOP参数path有过多符号连接问题EIOI/O存取错误代码示例:文件状态:#include #include #include #include

    展开阅读全文
    提示  163文库所有资源均是用户自行上传分享,仅供网友学习交流,未经上传用户书面授权,请勿作他用。
    关于本文
    本文标题:达内Unix编程.doc
    链接地址:https://www.163wenku.com/p-305605.html

    Copyright@ 2017-2037 Www.163WenKu.Com  网站版权所有  |  资源地图   
    IPC备案号:蜀ICP备2021032737号  | 川公网安备 51099002000191号


    侵权投诉QQ:3464097650  资料上传QQ:3464097650
       


    【声明】本站为“文档C2C交易模式”,即用户上传的文档直接卖给(下载)用户,本站只是网络空间服务平台,本站所有原创文档下载所得归上传人所有,如您发现上传作品侵犯了您的版权,请立刻联系我们并提供证据,我们将在3个工作日内予以改正。

    163文库