实验五(5) Linux C文件系统与文件操作(笔记)

实验五(一) Linux C文件系统与文件操作(笔记)

一 、实验目的:
1.掌握文件以及缓冲文件系统、文件指针的概念;
2.学会使用文件打开、关闭、读、写等文件操作函数;
3.学会用缓冲文件系统对文件进行简单的操作;
4.非缓冲文件的操作。

二、实验设备:
1.硬件 PC机
2.软件 VMware Workstation、Linux

三、实验内容:
编写程序并上机调试运行。
1.新建一个源文件如:f1.c编程实现:打开a.txt文本文件,读取其中内容,将其中小写字母转换为大写字母后,复制到b.txt新建文件中。

#include 
#include 
int main(){
char ch;
FILE *fp1,*fp2;
if((fp1=fopen("a.txt","r"))==NULL){
	printf("file open error!\n");
	exit(0);
}
if((fp2=fopen("b.txt","w"))==NULL){
	printf("file open error!\n");
	exit(0);
}
while((ch=fgetc(fp1))!=EOF){
	if(isalpha(ch) && islower(ch))
		ch=ch-0x20;
	fputc(ch,fp2);
}  
fclose(fp1);
fclose(fp2);
return 0; 	
}

2.新建一个源文件如:f2.c编程实现:程序打开某个文本文件,然后把此文件中的小写字母转换为大写字母其他字符不变,其中文件名作为命令行参数。

#include 
#include 
#include 
#include 
#include 
#define PERMS 0666
#define DUMMY 0
#define BUFSIZE 1024
int main(int argc,char *argv[]){
int fd,num,i,num2;
char iobuffer[BUFSIZE];
if(argc!=2){
	printf("file error!\n");
	return 1;  
}
if((fd=open(*(argv+1),O_RDWR,PERMS))==-1){
	printf("Source file open error!\n");
	return 2;
} 
num=read(fd,iobuffer,BUFSIZE);
for(i=0;i=97&&iobuffer[i]<=122)
		iobuffer[i]=iobuffer[i]-32;
}
lseek(fd,0,SEEK_SET);
num2=write(fd,iobuffer,num);
if(num2!=num){
	printf("write error!\n");
	return 3;
}
close(fd);
return 0;
}

3.新建一个源文件如:f3.c编程实现:程序从键盘接收多个字符,直到输入#字符,输入结束,然后,程序把这些输入的字符写入文件 file.txt中。

#include
#include
int main(){   
FILE *fp;
char ch;
if((fp=fopen("file.txt","w"))==NULL){
	printf("cannot open this file\n");
	exit(0);
}
else{
	printf("file open successful--writeonly\n");
}
printf("Input character from keybord and end input with charater'#'\n");
while(1){
	ch=getchar();
	//填空
	//填空
}
fputc(0x0d,fp);
fputc(0x0a,fp);
if(fclose(fp)==0){
	printf("file write successful and closed\n");
}
if((fp=fopen("file.txt","r"))==NULL){
	printf("cannot open this file\n");
	exit(0);
}
else{
	printf("file open successful--readonly\n");
}
printf("Input character from keybord and end input with charater'#'\n");
while(1){
	ch=fgetc(fp);
	if(ch!=EOF)  
		printf("%c",ch);
	else 
		break;
}
if(fclose(fp)==0){
	printf("file read  sucessful and closed\n");
}
return 0;
}

4.编写一个程序f4.c,实现文件改名操作。

#include 
int main(int argc,char **argv){
if(argc<3){
	printf("Usage: %s old_name new_name\n",argv[0]);
	return 0;
}
printf("%s=>%s",argv[1],argv[2]);
if(rename(argv[1],argv[2])<0)
	printf("error!\n");
else
	printf("ok!\n");
return 0;
}
  1. 编写一个程序f5.c,实现改变文件拥有者。

     #include
     #include
     main(){
     	chown("a.txt",0,0); 
     } 
    
  2. 编写一个程序f6.c,实现修改文件的访问权限

    #include 
     	#include 
     	main(){ 
     		chmod("a.txt",S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); 
     	}
    
  3. 编写一个程序f7.c,读取一个目录中的内容。(修改代码,执行时读取指定的某个目录)

    #include 
     struct dirent *readdir(DIR *dir);
     struct dirent {
     	long d_ino;//文件Inode号
     	off_td_off;//文件在目录文件中位置偏移
     	unsigned short int d_reclen;//文件名长
     	unsigned char d_type;//文件类型
     	char d_name[256];//文件名
     };
    

程序代码:

#include  
#include  
#include 
main(){  
DIR * dir; 
struct dirent * ptr; 
int i; 
dir =opendir("/etc/rc.d"); 
while((ptr = readdir(dir))!=NULL) {
	printf("d_name: %s\n",ptr->d_name); 
} 
closedir(dir); 
}  
  1. 编写一个程序f8.c,读取一个目录中的内容及其子目录中的内容。(修改代码,执行时读取指定的某个目录)

     # include 
     # include 
     # include 
     # include 
     # include 
     # include 
     int re_readdir(char name[]){
     char str[1000] = {0};
     strcpy(str, name);
     printf("%s\n", str);
     DIR *dir = opendir(str);
     if(NULL == dir){
     	perror("opendir");
     	return -1;
     }
     struct dirent *ent = readdir(dir);
     while(NULL != ent){
     	strcpy(str,name);
     	printf("name = %s: type = %d\n", ent->d_name, ent->d_type);
     	if(4 == ent->d_type && strcmp(ent->d_name, ".") && strcmp(ent->d_name, "..")){
     		re_readdir(strcat(strcat(strcat(str,"/"), ent->d_name),"/"));
     	}
     	ent = readdir(dir);
     }
     closedir(dir);
     return 0;
     }
     int main(void){
     re_readdir("/boot");
     return 0;
     }
    
  2. 编写一个程序f9.c,将文件ttt的文件权限变成所有者,同组的人有读写权限,其他用户只有读的权限。

     #include 
     #include 
     #include  /* for chmod */
     #include  /* for chmod */
     int main(){
     system("touch ttt; ls -l |grep ttt");
     chmod("./ttt",S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
     system("ls -l |grep ttt");
     return 0;
     }
    
  3. 编写一个程序f10.c,获取文件的相关信息。
    Linux stat函数:
    表头文件:

     #include 
     #include 
    

定义函数: int stat(const char *file_name, struct stat *buf);
函数说明: 通过文件名filename获取文件信息,并保存在buf所指的结构体stat中
返回值: 执行成功则返回0,失败返回-1,错误代码存于errno

#include 
#include 
#include 
int  main(){
struct stat buf;
stat("/etc/hosts", &buf);
printf("/etc/hosts file size = %d, last update time is %s\n", buf.st_size,ctime(&buf.st_mtime));
return 0;
}

错误代码:
ENOENT 参数file_name指定的文件不存在
ENOTDIR 路径中的目录存在但却非真正的目录
ELOOP 欲打开的文件有过多符号连接问题,上限为16符号连接
EFAULT 参数buf为无效指针,指向无法存在的内存空间
EACCESS 存取文件时被拒绝
ENOMEM 核心内存不足
ENAMETOOLONG 参数file_name的路径名称太长

struct stat {
    dev_t         st_dev;       //文件使用的设备号
    ino_t         st_ino;       //节点
    mode_t        st_mode;      //文件的类型和存取的权限
    nlink_t       st_nlink;     //连到该文件的硬连接数目,刚建立的文件值为1
    uid_t         st_uid;       //用户ID
    gid_t         st_gid;       //组ID
    dev_t         st_rdev;      //(设备类型)若此文件为设备文件,则为其设备编号
    off_t         st_size;      //文件字节数(文件大小)
    unsigned long st_blksize;   //块大小(文件系统的I/O 缓冲区大小)
    unsigned long st_blocks;    //块数
    time_t        st_atime;     //最后一次访问时间
    time_t        st_mtime;     //最后一次修改时间
    time_t        st_ctime;     //最后一次改变时间(指属性)
};

先前所描述的st_mode 则定义了下列数种情况:
S_IFSOCK 0140000 socket
S_IFLNK 0120000 符号连接
S_IFREG 0100000 一般文件
S_IFDIR 0040000 目录
S_IFCHR 0020000 字符
S_IFIFO 0010000 先进先出
S_IRUSR(S_IREAD) 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_mode) 是否为一般文件
S_ISDIR (st_mode) 是否为目录
S_ISCHR (st_mode) 是否为字符文件
S_ISBLK (s3e) 是否为先进先出
S_ISSOCK (st_mode) 是否为socket

  1. 编写一个程序f11.c,创建一个文件。

    #include 
    #include 
    #include 
    #include 
    int main(void){
    int fd = creat("creat.txt",S_IRUSR|S_IWUSR|S_IXUSR);
    system("ls creat.txt -l");
    return EXIT_SUCCESS;
    }
    
  2. 编写一个程序f12.c,创建3个软连接,一个指向正常的文件,一个指向自己,一个指向不存在的文件。
    格式:int symlink(const char *oldpath, const char *newpath);
    代码:

    #include 
    #include 
    #include 
    int main(){
    if(symlink("read","read_link") == -1){
    	perror("read symlink ");
    	exit(1);
    }
    if(symlink("invalid","in_link") == -1){
    	perror("invalid symlink ");
    	exit(1);
    }
    if(symlink("self_link","self_link") == -1){
    	perror("self symlink ");
    	exit(1);
    }
    system("ls *link -l");
    return 0;
    }
    
  3. 编写一个程序f13.c,创建一个空的文件,然后创建一个指向它的硬连接,接着向链接文件中写入数据。
    格式:int link(const char *oldpath, const char *newpath);
    代码:

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    int main(){
    system("touch read");
    link("read","read_link");
    int fd = open("read_link",O_WRONLY);
    char *str = "hello world!\n";
    int ret = write(fd,str,strlen(str));
    if(ret == -1){
    	perror("write ");
    	exit(1);
    }
    system("cat read; rm read; ls read_link -l");
    return 0;
    }
    

上述代码的执行结果,说明:

实验五(二) 进程实验

实验目的:
利用Linux提供的系统调用设计程序,加深对进程概念的理解。体会系统进程调度的方法和效果。
实验内容: 编写使用系统调用的C 语言关于进程的程序,并分析运行结果。

一、用户标识(UID)和有效用户标识(EUID)
使用getuid函数和geteuid函数来获取当前进程的用户标识和有效用户标识
程序p1.c

#include
#include
#include
#include
int main(void){
FILE *fp;
char ch;
	printf("Current process UID:%ld\n",(long)getuid());
	printf("Current process EUID:%ld\n",(long)geteuid());	
        fp=fopen("abc.txt","r");
        while ((ch=fgetc(fp))!= EOF)
           putchar(ch);
	return 0;
}

由root用户在/home/um1/文件夹下建立文件abc.txt,并写入一些内容,保存,设置该文件权限为400,查看Linux用户,并分别以um1用户运行和root用户运行上面程序。
二、fork函数
通过fork函数并判断函数返回值,根据返回值来判断是在父进程还是子进程。
程序p2.c

#include
#include
#include
int main(void){
        pid_t pid;
        if((pid=fork())<0){       
		   printf("Cannot create the new process\n");
                return 1;
        }
        else if(pid==0){
                printf("In the child process!\n");
                return 0;
        }
        else{
                printf("In the parent process!\n");
                return 0;
        }
} 

调用fork函数后,其后代码会被父子进程分别执行。
程序p3.c

#include
#include
#include
int main(void)
{
	fork();
	printf("Will be executed twice\n");
	return 0;
}	

程序p0.c

#include 
#include 
#include 
int main(void)
{
   int i;
   for(i=0; i<3; i++){
      fork();
      printf("-%d\n",getpid());
   }
   return 0;
}

三、vfork函数
程序p4.c

#include
#include
#include
int g_var=0;
int main(void)
{
	pid_t pid;
	int var=1;
	printf("process id:%d\n",(long)getpid());
	printf("before execute the fork system call,g_var=%d var=%d\n",g_var,var);
	if((pid=fork())<0)
	{
		printf("Cannot create a new process");
		return 1;
	}
	else if(pid==0)
	{
		g_var++;
		var++;
		printf("process id1:%d,g_var=%d var=%d\n",(long)getpid(),g_var,var);
		_exit(0);
	}
	printf("process id2:%d,g_var=%d var=%d\n",(long)getpid(),g_var,var);
	return 0;
}

由上可知, 。
修改上面程序,将fork函数的语句进行替换,使用vfork函数,将代码保存并运行:
程序p5.c

#include
#include
#include
int g_var=0;
int main(void)
{
	pid_t pid;
	int var=1;
	printf("process id:%d\n",(long)getpid());
	printf("before execute the fork system call,g_var=%d var=%d\n",g_var,var);
	if((pid=vfork())<0)
	{
		printf("Cannot create a new process");
		return 1;
	}
	else if(pid==0)
	{
		g_var++;
		var++;
		printf("process id1:%d,g_var=%d var=%d\n",(long)getpid(),g_var,var);
		_exit(0);
	}
	printf("process id2:%d,g_var=%d var=%d\n",(long)getpid(),g_var,var);
	return 0;
}

由上可知, 。
四、exec函数族
execvp函数支持参数列表,使用参数列表将使程序获得更大的灵活性,程序通过读取agrv中的参数,实现对输入的shell命令的执行。
程序p6.c

#include
#include
int main(int argc,char *argv[])
{
        if(argc<2)
        {
                printf("Usage: %s path\n",argv[0]);
                return 1;
        }
        execlp("/bin/ls","ls",argv[1],(char *)NULL);
        return 0;
}

程序的功能是调用shell命令中的“ls”,例如在linux终端:
(1)只输入一位main函数参数:“p6”

[root@BC test]# ./p6

其中path为文件或者目录的路径,而“./p6”则比拟为“ls”
(2)输入一个文件或目录的路径

[root@BC test]# ./p6 /home/bc

(3)此程序与“ls”区别是:要显示当前目录的内容,“ls”只输入“ls”然后回车即可;而此程序需要输入“./p6 ./”,即要加上“./”当前目录路径。

五、exit 函数
使用atexit注册了一个在进程退出时的处理函数,该处理函数只是显示一段文字信息。Main函数退出时将调用exit函数,这样进程就会在退出时自动调用atexit注册的函数。
程序p7.c

#include
#include
#include
void do_at_exit(void)
{
        printf("You can see the output when the progrom terminates\n");
}
int main()
{
        int flag;
        flag=atexit(do_at_exit);
        if(flag!=0)
        {
                printf("Cannot set exit function\n");
                return EXIT_FAILURE;
        }
        exit(EXIT_SUCCESS);
		printf("OK");		/*检验exit()直接调用atexit注册函数退出*/
}

运行结果:

[root@BC test]# ./p7

由上面程序可知, atexit注册函数成功返回值为0,所以flag的值为0,exit()直接调用atexit注册函数退出
_exit函数
下面的程序和上面的除了退出函数不同,其他都一样。不同的是使用_exit函数退出时,不会执行atexit中注册的处理函数。
程序p8.c

#include
#include
#include
void do_at_exit(void)
{
	printf("You can see the output when the progrom terminates\n");
}
int main()
{
	int flag;
	flag=atexit(do_at_exit);
	if(flag!=0)
	{
		printf("Cannot set exit function\n");
		return EXIT_FAILURE;
	}
	_exit(EXIT_SUCCESS);
}

运行结果:

[root@BC test]# ./p8

执行_exit函数与exit函数,内核都会将打开的文件关闭,将使用的内存地址空间释放,但前者不同是不处理打开的流缓冲区。
六、kill 函数发送信号
直接用kill函数给进程发送结束信号或是让进程自动退出。
程序p9.c

#include
#include
#include
#include
int main(int argc,char*argv[])
{
	int h;					/*定义一个变量,便于观察if语句的判断*/
	pid_t pid;
	int exit_code;
	pid=getpid();
	printf("%d\n",pid);
	srand((unsigned)pid);           
/*以pid产生随机数种子,默认随机数种子是1,如每次seed设相同值,*/
/*rand()所产生的随机数值每次就会一样*/
	exit_code=(int)(rand()%256);	/*exit_code的十六进制值不超过ff*/
	sleep(1);
	h=atoi(*(argv+1))%2;  
/*atoi()把字符转换为整型,参数为字母时返回0,h的值为0或1*/
	printf("%d\n ",h);
	if(h)						/*h=1时,执行语句*/
	{
		printf("the child process id:%d recive signal SIGKILL\n",pid);
		kill(pid,9);
	}
	else
	{
		printf("the child process id:%d normally exit_code is %0x\n",pid,exit_code);
	exit(exit_code);
	}
}

运行结果:

[root@BC test]# ./p9 4
the child process id:2536 normally exit_code is 25
[root@BC test]# ./p9 5
the child process id:2537 recive signal SIGKILL
Killed
[root@BC test]# ./p9 a
the child process id:**** normally exit_code is c1

由上可知,程序输入的第二参数argv[1],

下面程序通过fork函数创建子程序,并调用execl函数执行上面的程序。为方便了解程序运行的情况,在父进程中显示了创建的子进程的进程号。在while循环中调用wait函数,跳出条件是wait函数返回值小于0,或wait_pid为-1。这种情况下,所有的子进程都已经完全退出。
程序p10.c

#include
#include
#include
#include
int main(int argc,char*argv[])
{
	pid_t pid,wait_pid;
	int status;		
	int i;
	if(argc<4)
	{
		printf("Usage:%s para1 para2 para3\n",argv[0]);
		return 1;
	}
	for(i=1;i<4;i++)
		if((pid=fork())==0)
			execl("./p10","p10",argv[i],NULL);
		else
			printf("create the child process id:%d\n",pid);
	while((wait_pid=wait(&status))&&wait_pid!=-1)
		printf("process id:%d exit,exit_code is %0x\n",wait_pid,status);
	return 0;
}

运行结果:
(1)[root@BC test]# ./p10 dfdf dfd
(2)[root@BC test]# ./p10 1 2 a
分析运行结果,说明执行流程:
七、waitpid函数
使用waitpid等待SIGSTOP,SIGCONT和SIGKILL这三种信号。Waitpid第三参数为0时,父进程阻塞,为WNOHANG时,如果pid指定的子进程没有结束,则waitpid()函数立即返回0,而不是阻塞在这个函数上等待;如果结束了,则返回该子进程的进程号。
为WUNTRACED时,如果子进程进入暂停状态,则马上返回。。
程序p11.c

#include
#include
#include
#include
int main(void)
{
	pid_t pid,wait_pid;
	int status;
	pid=fork();
	if(pid==-1)
	{
		perror("Cannot creat new process");
		exit(1);
	}
	else
	if(pid==0)
	{
		printf("child process id:%d\n",(long)getpid());
		alarm(1);            // 给一个时钟信号,终止子进程
		pause();
		puts("pause");		// 检查_exit()有没有执行
		_exit(0);
	}
	else{
		do
		{
			wait_pid=waitpid(pid,&status,0);   // 此时pid>0,等待子进程结束
			if(wait_pid==-1){
					perror("cannot using waitpid function\n");
					exit(1);
			}
            if(WIFEXITED(status))    //子进程正常终止,则返回真
			   printf("child process exites,status=%d\n",WEXITSTATUS(status));
		    if(WIFSIGNALED(status))  //子进程由信号终止,则返回真
			   printf("child process is killed by signal %d\n",WTERMSIG(status));
			if(WIFSTOPPED(status))   //信号导致子进程停止,则返回真
			   printf("child process is stopped by signal %d\n",WSTOPSIG(status));
			//if(WIFCONTINUED(status)) //信号导致子进程继续执行,则返回真
			//	printf("child process resume running...\n");
		}
        while(!WIFEXITED(status)&&!WIFSIGNALED(status)); 
//信号或正常终止,则跳出循环
		exit(0);
	    }
}

运行结果:[root@BC test]# ./p11
(1)如果去掉第十九行与二十行代码

//alarm(1);
//pause();

运行结果:[root@BC test]# ./p11
使用alarm函数定时,然后通过pause()等待alarm函数的信号,pause函数使调用进程挂起直至捕捉到这个信号。对比执行结果,说明
alarm()函数-给闹钟定义处理函数。(定时1次)
程序p111.c

#include 
#include 
#include 
#include 
     
void handler()
{
  printf("hello\n");
}
 
void main()
{
  int i;
  signal(SIGALRM, handler);
  alarm(3);
  for(i = 1; i < 7; i++)
  {
    printf("sleep %d ...\n", i);
    sleep(1);
  }
}

setitimer函数-定义精确定时。(定时多次)
程序p112.c

#include         //printf()
#include         //pause()
#include         //signal()
#include         //memset()
#include     //struct itimerval, setitimer()

static int count = 0;
void printMes(int signo)
{
    printf("Get a SIGALRM, %d counts!\n", ++count);
}
int main()
{
    int res = 0;
    struct itimerval tick;
    
    signal(SIGALRM, printMes);
    memset(&tick, 0, sizeof(tick));
    //Timeout to run first time
    tick.it_value.tv_sec = 1;
    tick.it_value.tv_usec = 0;
    //After first, the Interval time for clock
    tick.it_interval.tv_sec = 1;
    tick.it_interval.tv_usec = 0;

    if(setitimer(ITIMER_REAL, &tick, NULL) < 0)
            printf("Set timer failed!\n");
    while(1)
    {
        pause();
    }
    return 0;
}

其中,which为定时器类型,3中类型定时器如下:
  ITIMER_REAL : 以系统真实的时间来计算,不管它是否在运行,计时到,它送出SIGALRM信号。
  ITIMER_VIRTUAL : 以该进程在用户态下运行时时间来计算,它送出SIGVTALRM信号。  
  ITIMER_PROF : 以该进程在用户态下和内核态下运行时时间来计算,它送出SIGPROF信号。
  第二个参数指定间隔时间,第三个参数用来返回上一次定时器的间隔时间,如果不关心该值可设为NULL。
  it_interval指定间隔时间,it_value指定初始定时时间。如果只指定it_value,就是实现一次定时;如果同时指定 it_interval,则超时后,系统会重新初始化it_value为it_interval,实现重复定时;两者都清零,则会清除定时器。  
  tv_sec提供秒级精度,tv_usec提供微秒级精度,以值大的为先,注意1s = 1000000us。 
  如果是以setitimer提供的定时器来休眠,只需阻塞等待定时器信号就可以了。
  setitimer()调用成功返回0,否则返回-1。
八、信号signal函数

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

signal函数
作用1:站在应用程序的角度,注册一个信号处理函数
作用2:忽略信号,设置信号默认处理
参数:
–signal是一个带signum和handler两个参数的函数,准备捕捉或屏蔽的信号由参数signum给出,接收到指定信号时将要调用的函数有handler给出。
–handler这个函数必须有一个int类型的参数(即接收到的信号代码),它本身的类型是void
–handler也可以是下面两个特殊值:① SIG_IGN 屏蔽该信号② SIG_DFL 恢复默认行为
p12.c
//忽略,屏蔽信号

#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int arg, char *args[])
{
    pid_t pid=fork();
    if(pid==-1)
    {
        printf("fork() failed! error message:%s\n",strerror(errno));
        return -1;
    }
    //注册信号,屏蔽SIGCHLD信号,子进程退出,将不会给父进程发送信号
    signal(SIGCHLD,SIG_IGN);
    if(pid>0)
    {
        printf("father is runing !\n");
        sleep(10);
    }
    if(pid==0)
    {
        printf("i am child!\n");
        exit(0);
    }
    printf("game over!\n");
    return 0;
}

p13.c

//恢复信号
#include 
#include 
#include 
#include 
#include 
#include 
#include 

void catch_signal(int sign)
{
    switch (sign)
    {
    case SIGINT:
        printf("ctrl + C is executed!\n");
        //exit(0);
        break;
    }
}

int main(int arg, char *args[])
{
    //注册终端中断信号
    signal(SIGINT, catch_signal);
    char tempc = 0;
    while ((tempc = getchar()) != 'a')
    {
        printf("tempc=%d\n", tempc);
        //sleep()
    }
    //恢复信号
    signal(SIGINT, SIG_DFL);
    while (1)
    {
        pause();
    }
    printf("game over!\n");
    return 0;
}

p14.c
//sleep 函数

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

void catch_signal(int sign)
{
    switch(sign)
    {
    case SIGINT:
        printf("accept signal!\n");
        break;
    default:
        break;
    }
}

int main(int arg,char *args[])
{
    //注册信号
    if(signal(SIGINT,catch_signal)==SIG_ERR)
    {
        perror("signal error");
        return-1;
    }
    int num=0;
    num=sleep(100);
    //手动执行 ctrl+C  进程被唤醒
    if(num>0)
    {
        printf("sleep()函数被打算睡眠,醒过来了!\n");
    }
    //说明:sleep()函数是可中断睡眠
    printf("新的测试!\n");
    //再次设计sleep()函数,让其sleep需要的时间
    num=15;
    do{
        num=sleep(num);
        printf("被唤醒了,但是还要继续睡眠!剩余时间%d\n",num);
    }while(num);
    printf("game over!\n");
    return 0;
}

你可能感兴趣的:(Linux)