实验四Linux下的C语言编程.docx
《实验四Linux下的C语言编程.docx》由会员分享,可在线阅读,更多相关《实验四Linux下的C语言编程.docx(15页珍藏版)》请在冰豆网上搜索。
实验四Linux下的C语言编程
实验报告
课程名称Linux系统实践__
实验项目Linux下的C语言编程
实验仪器PC___________
系别计算机学院___
专业网络工程____
班级/学号网1702/2017011463
学生孟启贤_____
实验日期5.13______
成绩___________________
指导教师艳平____
实验四Linux下的C语言编程
实验类别:
设计型实验时数:
6学时
开课单位:
计算机学院实验地点:
健翔校区计算中心
一、实验目的
通过本实验练习,使学生掌握有关文件管理与文件操作的容。
首先要熟悉在LINUX系统下文件系统的构建方法;其次要熟练掌握在LINUX
环境下用C语言进行高级编程的方法(即有关文件操作的系统调用的使用),进而充分了解LINUX文件系统中shell命令的实现原理以及用到的系统调用。
二、实验环境
操作系统:
任何Unix/Linux或MAC
编译器:
gcc
三、预备知识
1、关于系统调用和库函数
C语言支持一系列的库函数的调用,其中最基本的是studio库函数。
事实上,库函数只是C语言在较高层次上调用的方式,系统调用是更低层次的与C语言的界面,是核提供给用户调用的函数。
2、LINUX环境下系统调用和库函数的异同
⑴C程序使用系统调用的语句和调用库函数的语句形式完全相同,但是
二者运行的环境和运行机制截然不同。
⑵从运行环境来看,库函数使用依赖于所运行的用户环境,程序调用库
函数时,它运行的目标代码是属于程序的,程序处于“用户态”执行;而系统调用的使用不依赖于它运行的用户环境,是LINUX核提供
的低层服务,系统调用时所执行的代码是属于核的,程序处于“核
心态”执行。
⑶程序库函数的调用最终还是要通过LINUX系统调用来实现,库函数一般执行一条指令,该指令(操作系统陷阱operatingsystem
trap)将进程执行方式变为核心态,然后使核为系统调用执行代码。
四
(1)、实验容
本实验要求在LINUX/UNIX环境下用C语言完成SHELL命令的编写,基本涉及了LINUX/UNIX文件系统中较为常用的有关文件操作的系统调用。
容如下:
1、编程实现lnk命令,执行格式:
lnkf1f2f3。
具体要求如下:
⑴分别使用link()和symlink()为文件f1(任意)创建其硬文件f2和符号文件f3。
⑵分别使用stat()和lstat()调用给出文件f2和f3的索引节点号、权限、存放该文件的设备号及文件修改时间,比较其异同。
说明原因。
#include
#include
#include
#include
#include
intmain(intargc,charconst*argv[]){
structstatbuf;
if(argc!
=4)
{
printf("inputerror\n");
return0;
}
if(link(argv[1],argv[2])==-1)
{
printf("linkerror\n");
return0;
}
if(symlink(argv[1],argv[3])==-1)
{
printf("symlinkerror\n");
return0;
}
if(stat(argv[2],&buf)==-1)
{
printf("statf2error\n");
return0;
}
printf("statf2\n");
printf("索引号节点号:
%ld\n",buf.st_ino);
printf("权限:
%o\n",buf.st_mode);
printf("设备号:
%ld\n",buf.st_dev);
printf("文件修改时间:
%ld\n",buf.st_mtime);
if(stat(argv[3],&buf)==-1)
{
printf("statf3error\n");
return0;
}
printf("statf3\n");
printf("索引号节点号:
%ld\n",buf.st_ino);
printf("权限:
%o\n",buf.st_mode);
printf("设备号:
%ld\n",buf.st_dev);
printf("文件修改时间:
%ld\n",buf.st_mtime);
if(lstat(argv[2],&buf)<0)
{
printf("lstatf2error\n");
return0;
}
printf("lstatf2\n");
printf("索引号节点号:
%ld\n",buf.st_ino);
printf("权限:
%o\n",buf.st_mode);
printf("设备号:
%ld\n",buf.st_dev);
printf("文件修改时间:
%ld\n",buf.st_mtime);
if(lstat(argv[3],&buf)<0)
{
printf("lstatf3error\n");
return0;
}
printf("lstatf3\n");
printf("索引号节点号:
%ld\n",buf.st_ino);
printf("权限:
%o\n",buf.st_mode);
printf("设备号:
%ld\n",buf.st_dev);
printf("文件修改时间:
%ld\n",buf.st_mtime);
printf("finished");
return0;
}
结果如下:
原因:
Stat对于硬和软连接都是返回所指文件的信息。
但是对于lstst,如果文件是符号,lstat返回的是符号本身的信息。
2、编程实现copy命令,执行格式:
copycj.txtf1
功能:
⑴复制前先将文件f1(见1)的容清空;
⑵分别使用fstat()、stat()和lstat()调用给出文件f1、f2和f3大
小及最近一次状态改变的时间;
⑶将实验三新创建文件cj.txt中前100个字节的容拷入f1中,在其后创建30个字节的空洞,然后再复制cj.txt中第141个字节之后的容到f1中;
⑷复制成功后,显示文件f2的大小及文件f1的容。
上述功能实现后可将空洞调大到几十~几百MB,然后用du命令显示文件f1占用的磁盘空间,观察其大小,分析原因。
问题:
①上述第⑵项中用fstat()替换stat()显示文件f2的信息可以吗?
为
什么?
答:
不可以,fstat是用文件的描述符指向文件。
②比较上述第⑷项和第⑵项的结果,文件f2的大小为何有变化?
F2是f1的硬,本质是一个文件,前面是对f1容清空了,后面在f1中放入了一些容,所以大小改变了。
程序可能涉及到的系统调用:
read(),write(),open(),creat(),close(),lseek(),stat(),fstat(),lstat()
#include
#include
#include
#include
#include
intmain(intargc,char*argv[])
{
chars;
structstatbuf;
if(argc!
=3)
{
printf("inputerror\n");
return0;
}
/*f1*/
inta=open("f1",O_CREAT|O_TRUNC|O_RDWR);
if(a==-1)
{
printf("ERROR!
");
}
if(stat("f1",&buf)==-1)
{
printf("statf1error\n");
return0;
}
printf("statf1\n");
printf("大小:
%ld\n",buf.st_size);
printf("最近一次状态时间:
%ld\n\n",buf.st_ctime);
if(lstat("f1",&buf)<0)
{
printf("lstatf1error\n");
return0;
}
printf("lstatf1\n");
printf("大小:
%ld\n",buf.st_size);
printf("最近一次状态时间:
%ld\n\n",buf.st_ctime);
if(fstat(a,&buf)<0)
{
printf("fstatf1error\n");
return0;
}
printf("fstatf1\n");
printf("大小:
%ld\n",buf.st_size);
printf("最近一次状态时间:
%ld\n\n",buf.st_ctime);
/*f2*/
intb=open("f2",O_CREAT|O_TRUNC);
if(b==-1)
{
printf("ERROR!
");
}
if(stat("f2",&buf)==-1)
{
printf("statf2error\n");
return0;
}
printf("statf2\n");
printf("大小:
%ld\n",buf.st_size);
printf("最近一次状态时间:
%ld\n\n",buf.st_ctime);
if(lstat("f2",&buf)<0)
{
printf("lstatf2error\n");
return0;
}
printf("lstatf2\n");
printf("大小:
%ld\n",buf.st_size);
printf("最近一次状态时间:
%ld\n\n",buf.st_ctime);
if(fstat(b,&buf)<0)
{
printf("fstatf2error\n");
return0;
}
printf("fstatf2\n");
printf("大小:
%ld\n",buf.st_size);
printf("最近一次状态时间:
%ld\n",buf.st_ctime);
close(b);
/*f3*/
intc=open("f3",O_CREAT|O_TRUNC);
if(c==-1)
{
printf("ERROR!
");
}
if(stat("f3",&buf)==-1)
{
printf("statf3error\n");
return0;
}
printf("statf3\n");
printf("大小:
%ld\n",buf.st_size);
printf("最近一次状态时间:
%ld\n\n",buf.st_ctime);
if(lstat("f3",&buf)<0)
{
printf("lstatf3error\n");
return0;
}
printf("lstatf3\n");
printf("大小:
%ld\n",buf.st_size);
printf("最近一次状态时间:
%ld\n\n",buf.st_ctime);
if(fstat(c,&buf)<0)
{
printf("fstatf3error\n");
return0;
}
printf("fstatf3\n");
printf("大小:
%ld\n",buf.st_size);
printf("最近一次状态时间:
%ld\n\n",buf.st_ctime);
close(c);
intd=open("cj.txt",O_CREAT|O_RDWR);
if(d==-1){
printf("ERROR!
");
}
/*inte=open("f1",O_CREAT|O_TRUNC|O_RDWR);
if(e==-1)
{
printf("ERROR!
");
}*/
intn;
if((n=read(d,&buf,100))>0)
{
if(write(a,&buf,n)!
=n)
{printf("a/writeerror\n");}
}
if(n<0)
{
printf("readerror\n");
}
if(lseek(d,141,SEEK_SET)==-1)
{
printf("error!
");
}
intm;
if(lseek(a,30,SEEK_CUR)==-1)
{
printf("error!
");
}
charbuf2[1000];
if((m=read(d,buf2,1000))>0)
{
if(write(a,buf2,m)!
=m)
{printf("d/writeerror\n");}
}
if(m<=0)
{
printf("readerror\n");
}
if(stat("f2",&buf)==-1)
{
printf("statf2error\n");
return0;
}
printf("statf2的大小\n");
printf("大小:
%ld\n",buf.st_size);
close(a);
intz=open(“f1”,O_RDONLY);
while(read(z,s,1)){
printf("%c",s);
}
printf("\n");
close(d);
close(a);
return0;
}
截图如下:
四
(2)实验总结
通过这次实验熟悉了linux下文件系统的构建方法,学会了如何使用gcc编译c文件,和使用out的输入和操作。
更加熟悉了read()、open()、lseek()等等的使用方法,以及他们的反映执行结果的返回值,也明白了硬和软连接的区别,以及stat和lstat了解文件信息,以及他们的区别。
五、实验要求
1、做好实验预习,通过查找资料、阅读系统提供的帮助文件等多种渠道了解本实验所使用的系统调用及各种技术方法。
充分利用所学知识,尽可能多地预设实现思路。
2、写出实验报告,容是:
⑴简要说明实验的目的、任务与设备。
⑵写出实现的技术手段及关键代码。
⑶总结设计中遇到的问题及解决方法。
⑷写出实验心得与收获。
六、使用系统调用时的注意事项
以下列出了几条系统调用和库函数有关出错处理的不同点,更多的容还需大家通过编程积累。
⑴对于studio库中的函数,出错时会返回一个预定义的常量EOF或NULL;许多库函数在出错时常常返回0或–1;有些库函数则返
回某种出错代码。
⑵系统调用的出错处理比较简单,每个系统调用在出错时都返回–1,
在调用成功时返回0(或某些其他具有特定意义的整数值)。
LINUX系
统调用把出错代码放在一个名为error的外部变量中,在程序中包含头文件error.h,便可以得到error的错误代码。