版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
linux操作系統(tǒng)下c語言編程入門[轉]-----非常經(jīng)典的文章linux操作系統(tǒng)下c語言編程入門
(一)目錄介紹
1)Linux程序設計入門--基礎知識
2)Linux程序設計入門--進程介紹
3)Linux程序設計入門--文件操作
4)Linux程序設計入門--時間概念
5)Linux程序設計入門--信號處理
6)Linux程序設計入門--消息管理
7)Linux程序設計入門--線程操作
8)Linux程序設計入門--網(wǎng)絡編程
9)Linux下C開發(fā)工具介紹
(二)具體內容
1)Linux程序設計入門--基礎知識
Linux下C語言編程基礎知識
前言:
這篇文章介紹在LINUX下進行C語言編程所需要的基礎知識.在這篇文章當中,我們將
會學到以下內容:
源程序編譯
Makefile的編寫
程序庫的鏈接
程序的調試
頭文件和系統(tǒng)求助
1.源程序的編譯
在Linux下面,如果要編譯一個C語言源程序,我們要使用GNU的gcc編譯器.下面我們
以一個實例來說明如何使用gcc編譯器.
假設我們有下面一個非常簡單的源程序(hello.c):
intmain(intargc,char**argv)
{
printf("HelloLinux/n");
}
要編譯這個程序,我們只要在命令行下執(zhí)行:
gcc-ohellohello.c
gcc編譯器就會為我們生成一個hello的可執(zhí)行文件.執(zhí)行./hello就可以看到程序的輸出結果了.命令行中gcc表示我們是用gcc來編譯我們的源程序,-o選項表示我們要求編譯器給我們輸出的可執(zhí)行文件名為hello而hello.c是我們的源程序文件.
gcc編譯器有許多選項,一般來說我們只要知道其中的幾個就夠了.-o選項我們已經(jīng)知道了,表示我們要求輸出的可執(zhí)行文件名.-c選項表示我們只要求編譯器輸出目標代碼,而不必要輸出可執(zhí)行文件.-g選項表示我們要求編譯器在編譯的時候提供我們以后對程序進行調試的信息.
知道了這三個選項,我們就可以編譯我們自己所寫的簡單的源程序了,如果你想要知道更多的選項,可以查看gcc的幫助文檔,那里有著許多對其它選項的詳細說明.
2.Makefile的編寫
假設我們有下面這樣的一個程序,源代碼如下:
/*main.c*/
#include"mytool1.h"
#include"mytool2.h"
intmain(intargc,char**argv)
{
mytool1_print("hello");
mytool2_print("hello");
}
/*mytool1.h*/
#ifndef_MYTOOL_1_H
#define_MYTOOL_1_H
voidmytool1_print(char*print_str);
#endif
/*mytool1.c*/
#include"mytool1.h"
voidmytool1_print(char*print_str)
{
printf("Thisismytool1print%s/n",print_str);
}
/*mytool2.h*/
#ifndef_MYTOOL_2_H
#define_MYTOOL_2_H
voidmytool2_print(char*print_str);
#endif
/*mytool2.c*/
#include"mytool2.h"
voidmytool2_print(char*print_str)
{
printf("Thisismytool2print%s/n",print_str);
}
當然由于這個程序是很短的我們可以這樣來編譯
gcc-cmain.c
gcc-cmytool1.c
gcc-cmytool2.c
gcc-omainmain.omytool1.omytool2.o
這樣的話我們也可以產(chǎn)生main程序,而且也不是很麻煩.但是如果我們考慮一下如果有一天我們修改了其中的一個文件(比如說mytool1.c)那么我們難道還要重新輸入上面的命令?也許你會說,這個很容易解決啊,我寫一個SHELL腳本,讓她幫我去完成不就可以了.是的
對于這個程序來說,是可以起到作用的.但是當我們把事情想的更復雜一點,如果我們的程
序有幾百個源程序的時候,難道也要編譯器重新一個一個的去編譯?
為此,聰明的程序員們想出了一個很好的工具來做這件事情,這就是make.我們只要執(zhí)行以
下make,就可以把上面的問題解決掉.在我們執(zhí)行make之前,我們要先編寫一個非常重要的
文件.--Makefile.對于上面的那個程序來說,可能的一個Makefile的文件是:
#這是上面那個程序的Makefile文件
main:main.omytool1.omytool2.o
gcc-omainmain.omytool1.omytool2.o
main.o:main.cmytool1.hmytool2.h
gcc-cmain.c
mytool1.o:mytool1.cmytool1.h
gcc-cmytool1.c
mytool2.o:mytool2.cmytool2.h
gcc-cmytool2.c
有了這個Makefile文件,不過我們什么時候修改了源程序當中的什么文件,我們只要執(zhí)行
make命令,我們的編譯器都只會去編譯和我們修改的文件有關的文件,其它的文件她連理
都不想去理的.
下面我們學習Makefile是如何編寫的.
在Makefile中也#開始的行都是注釋行.Makefile中最重要的是描述文件的依賴關系的說
明.一般的格式是:
target:components
TABrule
第一行表示的是依賴關系.第二行是規(guī)則.
比如說我們上面的那個Makefile文件的第二行
main:main.omytool1.omytool2.o
表示我們的目標(target)main的依賴對象(components)是main.omytool1.omytool2.o
當倚賴的對象在目標修改后修改的話,就要去執(zhí)行規(guī)則一行所指定的命令.就象我們的上
面那個Makefile第三行所說的一樣要執(zhí)行gcc-omainmain.omytool1.omytool2.o
注意規(guī)則一行中的TAB表示那里是一個TAB鍵
Makefile有三個非常有用的變量.分別是$@,___FCKpd___0gt;,___FCKpd___0lt;代表的意義分別是:
$@--目標文件,$^--所有的依賴文件,___FCKpd___0lt;--第一個依賴文件.
如果我們使用上面三個變量,那么我們可以簡化我們的Makefile文件為:
#這是簡化后的Makefile
main:main.omytool1.omytool2.o
gcc-o$@___FCKpd___0gt;
main.o:main.cmytool1.hmytool2.h
gcc-c___FCKpd___0lt;
mytool1.o:mytool1.cmytool1.h
gcc-c___FCKpd___0lt;
mytool2.o:mytool2.cmytool2.h
gcc-c___FCKpd___0lt;
經(jīng)過簡化后我們的Makefile是簡單了一點,不過人們有時候還想簡單一點.這里我們學習
一個Makefile的缺省規(guī)則
..c.o:
gcc-c___FCKpd___0lt;
這個規(guī)則表示所有的.o文件都是依賴與相應的.c文件的.例如mytool.o依賴于mytool.c
這樣Makefile還可以變?yōu)?
#這是再一次簡化后的Makefile
main:main.omytool1.omytool2.o
gcc-o$@$^
..c.o:
gcc-c___FCKpd___0lt;
好了,我們的Makefile也差不多了,如果想知道更多的關于Makefile規(guī)則可以查看相應的
文檔.
3.程序庫的鏈接
試著編譯下面這個程序
/*temp.c*/
#include<math.h>
intmain(intargc,char**argv)
{
doublevalue;
printf("Value:%f/n",value);
}
這個程序相當簡單,但是當我們用gcc-otemptemp.c編譯時會出現(xiàn)下面所示的錯誤.
/tmp/cc33Kydu.o:Infunction`main':
/tmp/cc33Kydu.o(.text+0xe):undefinedreferenceto`log'
collect2:ldreturned1exitstatus
出現(xiàn)這個錯誤是因為編譯器找不到log的具體實現(xiàn).雖然我們包括了正確的頭文件,但是我
們在編譯的時候還是要連接確定的庫.在Linux下,為了使用數(shù)學函數(shù),我們必須和數(shù)學庫連接,為此我們要加入-lm選項.gcc-otemptemp.c-lm這樣才能夠正確的編譯.也許
有人要問,前面我們用printf函數(shù)的時候怎么沒有連接庫呢?是這樣的,對于一些常用的函
數(shù)的實現(xiàn),gcc編譯器會自動去連接一些常用庫,這樣我們就沒有必要自己去指定了.有時
候我們在編譯程序的時候還要指定庫的路徑,這個時候我們要用到編譯器的-L選項指定
路徑.比如說我們有一個庫在/home/hoyt/mylib下,這樣我們編譯的時候還要加上-L/home/hoyt/mylib.對于一些標準庫來說,我們沒有必要指出路徑.只要它們在起缺省庫的路
徑下就可以了.系統(tǒng)的缺省庫的路徑/lib/usr/lib/usr/local/lib在這三個路徑下面
的庫,我們可以不指定路徑.
還有一個問題,有時候我們使用了某個函數(shù),但是我們不知道庫的名字,這個時候怎么辦呢
?很抱歉,對于這個問題我也不知道答案,我只有一個傻辦法.首先,我到標準庫路徑下面去
找看看有沒有和我用的函數(shù)相關的庫,我就這樣找到了線程(thread)函數(shù)的庫文件(libpthread.a).當然,如果找不到,只有一個笨方法.比如我要找sin這個函數(shù)所在的庫.就只
好用nm-o/lib/*.so|grepsin>~/sin命令,然后看~/sin文件,到那里面去找了.在sin文件當中,我會找到這樣的一行l(wèi)ibm-2.1.2.so:00009fa0Wsin這樣我就知道了sin在
libm-2.1.2.so庫里面,我用-lm選項就可以了(去掉前面的lib和后面的版本標志,就剩
下m了所以是-lm).如果你知道怎么找,請趕快告訴我,我回非常感激的.謝謝!
4.程序的調試
我們編寫的程序不太可能一次性就會成功的,在我們的程序當中,會出現(xiàn)許許多多我
們想不到的錯誤,這個時候我們就要對我們的程序進行調試了.
最常用的調試軟件是gdb.如果你想在圖形界面下調試程序,那么你現(xiàn)在可以選擇xxgdb.記
得要在編譯的時候加入-g選項.關于gdb的使用可以看gdb的幫助文件.由于我沒有用過這
個軟件,所以我也不能夠說出如何使用.不過我不喜歡用gdb.跟蹤一個程序是很煩的事情
,我一般用在程序當中輸出中間變量的值來調試程序的.當然你可以選擇自己的辦法,沒有
必要去學別人的.現(xiàn)在有了許多IDE環(huán)境,里面已經(jīng)自己帶了調試器了.你可以選擇幾個試
一試找出自己喜歡的一個用.
5.頭文件和系統(tǒng)求助
有時候我們只知道一個函數(shù)的大概形式,不記得確切的表達式,或者是不記得著函數(shù)
在那個頭文件進行了說明.這個時候我們可以求助系統(tǒng).
比如說我們想知道fread這個函數(shù)的確切形式,我們只要執(zhí)行manfread系統(tǒng)就會輸出著
函數(shù)的詳細解釋的.和這個函數(shù)所在的頭文件<stdio.h>說明了.如果我們要write這個函
數(shù)的說明,當我們執(zhí)行manwrite時,輸出的結果卻不是我們所需要的.因為我們要的是write這個函數(shù)的說明,可是出來的卻是write這個命令的說明.為了得到write的函數(shù)說明
我們要用man2write.2表示我們用的write這個函數(shù)是系統(tǒng)調用函數(shù),還有一個我們常
用的是3表示函數(shù)是C的庫函數(shù).
記住不管什么時候,man都是我們的最好助手.
------------------------------------------------------------------------
好了,這一章就講這么多了,有了這些知識我們就可以進入激動人心的Linux下的C程序探險活動.
2)Linux程序設計入門--進程介紹
Linux下進程的創(chuàng)建
前言:
這篇文章是用來介紹在Linux下和進程相關的各個概念.我們將會學到:
進程的概念
進程的身份
進程的創(chuàng)建
守護進程的創(chuàng)建
1。進程的概念
Linux操作系統(tǒng)是面向多用戶的.在同一時間可以有許多用戶向操作系統(tǒng)發(fā)出各種命令.那么操作系統(tǒng)是怎么實現(xiàn)多用戶的環(huán)境呢?在現(xiàn)代的操作系統(tǒng)里面,都有程序和進程的概念.那么什么是程序,什么是進程呢?通俗的講程序是一個包含可以執(zhí)行代碼的文件,是一個靜態(tài)的文件.而進程是一個開始執(zhí)行但是還沒有結束的程序的實例.就是可執(zhí)行文件的具體實現(xiàn).一個程序可能有許多進程,而每一個進程又可以有許多子進程.依次循環(huán)下去,而產(chǎn)生子孫進程.當程序被系統(tǒng)調用到內存以后,系統(tǒng)會給程序分配一定的資源(內存,設備等等)然后進行一系列的復雜操作,使程序變成進程以供系統(tǒng)調用.在系統(tǒng)里面只有進程沒有程序,為了區(qū)分各個不同的進程,系統(tǒng)給每一個進程分配了一個ID(就象我們的身份證)以便識別.為了充分的利用資源,系統(tǒng)還對進程區(qū)分了不同的狀態(tài).將進程分為新
建,運行,阻塞,就緒和完成五個狀態(tài).新建表示進程正在被創(chuàng)建,運行是進程正在運行,阻塞是進程正在等待某一個事件發(fā)生,就緒是表示系統(tǒng)正在等待CPU來執(zhí)行命令,而完成表示進程已經(jīng)結束了系統(tǒng)正在回收資源.關于進程五個狀態(tài)的詳細解說我們可以看《操作系統(tǒng)》上面有詳細的解說。
2。進程的標志
上面我們知道了進程都有一個ID,那么我們怎么得到進程的ID呢?系統(tǒng)調用getpid可以得到進程的ID,而getppid可以得到父進程(創(chuàng)建調用該函數(shù)進程的進程)的ID.
#include<unistd>
pid_tgetpid(void);
pid_tgetppid(void);
進程是為程序服務的,而程序是為了用戶服務的.系統(tǒng)為了找到進程的用戶名,還為進程和用戶建立聯(lián)系.這個用戶稱為進程的所有者.相應的每一個用戶也有一個用戶ID.通過系統(tǒng)調用getuid可以得到進程的所有者的ID.由于進程要用到一些資源,而Linux對系統(tǒng)資源是進行保護的,為了獲取一定資源進程還有一個有效用戶ID.這個ID和系統(tǒng)的資源使用有關,涉及到進程的權限.通過系統(tǒng)調用geteuid我們可以得到進程的有效用戶ID.和用戶ID相對應進程還有一個組ID和有效組ID系統(tǒng)調用getgid和getegid可以分別得到組ID和有效組ID
#include<unistd>
#include<sys/types.h>
uid_tgetuid(void);
uid_tgeteuid(void);
gid_tgetgid(void);
git_tgetegid(void);
有時候我們還會對用戶的其他信息感興趣(登錄名等等),這個時候我們可以調用getpwuid來得到.
structpasswd{
char*pw_name;/*登錄名稱*/
char*pw_passwd;/*登錄口令*/
uid_tpw_uid;/*用戶ID*/
gid_tpw_gid;/*用戶組ID*/
char*pw_gecos;/*用戶的真名*/
char*pw_dir;/*用戶的目錄*/
char*pw_shell;/*用戶的SHELL*/
};
#include<pwd.h>
#include<sys/types.h>
structpasswd*getpwuid(uid_tuid);
下面我們學習一個實例來實踐一下上面我們所學習的幾個函數(shù):
#include<unistd.h>
#include<pwd.h>
#include<sys/types.h>
#include<stdio.h>
intmain(intargc,char**argv)
{
pid_tmy_pid,parent_pid;
uid_tmy_uid,my_euid;
gid_tmy_gid,my_egid;
structpasswd*my_info;
my_pid=getpid();
parent_pid=getppid();
my_uid=getuid();
my_euid=geteuid();
my_gid=getgid();
my_egid=getegid();
my_info=getpwuid(my_uid);
printf("ProcessID:%ld/n",my_pid);
printf("ParentID:%ld/n",parent_pid);
printf("UserID:%ld/n",my_uid);
printf("EffectiveUserID:%ld/n",my_euid);
printf("GroupID:%ld/n",my_gid);
printf("EffectiveGroupID:%ld/n",my_egid);
if(my_info)
{
printf("MyLoginName:%s/n",my_info->pw_name);
printf("MyPassword:%s/n",my_info->pw_passwd);
printf("MyUserID:%ld/n",my_info->pw_uid);
printf("MyGroupID:%ld/n",my_info->pw_gid);
printf("MyRealName:%s/n",my_info->pw_gecos);
printf("MyHomeDir:%s/n",my_info->pw_dir);
printf("MyWorkShell:%s/n",my_info->pw_shell);
}
}
3。進程的創(chuàng)建
創(chuàng)建一個進程的系統(tǒng)調用很簡單.我們只要調用fork函數(shù)就可以了.
#include<unistd.h>
pid_tfork();
當一個進程調用了fork以后,系統(tǒng)會創(chuàng)建一個子進程.這個子進程和父進程不同的地方只有他的進程ID和父進程ID,其他的都是一樣.就象符進程克隆(clone)自己一樣.當然創(chuàng)建兩個一模一樣的進程是沒有意義的.為了區(qū)分父進程和子進程,我們必須跟蹤fork的返回值.當fork掉用失敗的時候(內存不足或者是用戶的最大進程數(shù)已到)fork返回-1,否則fork的返回值有重要的作用.對于父進程fork返回子進程的ID,而對于fork子進程返回0.我們就是根據(jù)這個返回值來區(qū)分父子進程的.父進程為什么要創(chuàng)建子進程呢?前面我們已經(jīng)說過了Linux是一個多用戶操作系統(tǒng),在同一時間會有許多的用戶在爭奪系統(tǒng)的資源.有時進程為了早一點完成任務就創(chuàng)建子進程來爭奪資源.一旦子進程被創(chuàng)建,父子進程一起從fork處繼續(xù)執(zhí)行,相互競爭系統(tǒng)的資源.有時候我們希望子進程繼續(xù)執(zhí)行,而父進程阻塞直到子進程完成任務.這個時候我們可以調用wait或者waitpid系統(tǒng)調用.
#include<sys/types.h>
#include<sys/wait.h>
pid_twait(int*stat_loc);
pid_twaitpid(pid_tpid,int*stat_loc,intoptions);
wait系統(tǒng)調用會使父進程阻塞直到一個子進程結束或者是父進程接受到了一個信號.如果沒有父進程沒有子進程或者他的子進程已經(jīng)結束了wait回立即返回.成功時(因一個子進程結束)wait將返回子進程的ID,否則返回-1,并設置全局變量errno.stat_loc是子進程的退出狀態(tài).子進程調用exit,_exit或者是return來設置這個值.為了得到這個值Linux定義了幾個宏來測試這個返回值.
WIFEXITED:判斷子進程退出值是非0
WEXITSTATUS:判斷子進程的退出值(當子進程退出時非0).
WIFSIGNALED:子進程由于有沒有獲得的信號而退出.
WTERMSIG:子進程沒有獲得的信號號(在WIFSIGNALED為真時才有意義).
waitpid等待指定的子進程直到子進程返回.如果pid為正值則等待指定的進程(pid).如果為0則等待任何一個組ID和調用者的組ID相同的進程.為-1時等同于wait調用.小于-1時等待任何一個組ID等于pid絕對值的進程.stat_loc和wait的意義一樣.options可以決定父進程的狀態(tài).可以取兩個值WNOHANG:父進程立即返回當沒有子進程存在時.WUNTACHED:當子進程結束時waitpid返回,但是子進程的退出狀態(tài)不可得到.父進程創(chuàng)建子進程后,子進程一般要執(zhí)行不同的程序.為了調用系統(tǒng)程序,我們可以使用系統(tǒng)調用exec族調用.exec族調用有著5個函數(shù).
#include<unistd.h>
intexecl(constchar*path,constchar*arg,...);
intexeclp(constchar*file,constchar*arg,...);
intexecle(constchar*path,constchar*arg,...);
intexecv(constchar*path,char*constargv[]);
intexecvp(constchar*file,char*constargv[]):
exec族調用可以執(zhí)行給定程序.關于exec族調用的詳細解說可以參考系統(tǒng)手冊(manexec
l).下面我們來學習一個實例.注意編譯的時候要加-lm以便連接數(shù)學函數(shù)庫.
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<stdio.h>
#include<errno.h>
#include<math.h>
voidmain(void)
{
pid_tchild;
intstatus;
printf("Thiswilldemostratehowtogetchildstatus/n");
if((child=fork())==-1)
{
printf("ForkError:%s/n",strerror(errno));
exit(1);
}
elseif(child==0)
{
inti;
printf("Iamthechild:%ld/n",getpid());
for(i=0;i<1000000;i++)sin(i);
i=5;
printf("Iexitwith%d/n",i);
exit(i);
}
while(((child=wait(&status))==-1)&(errno==EINTR));
if(child==-1)
printf("WaitError:%s/n",strerror(errno));
elseif(!status)
printf("Child%ldterminatednormallyreturnstatusiszero/n",
child);
elseif(WIFEXITED(status))
printf("Child%ldterminatednormallyreturnstatusis%d/n",
child,WEXITSTATUS(status));
elseif(WIFSIGNALED(status))
printf("Child%ldterminatedduetosignal%dznotcaught/n",
child,WTERMSIG(status));
}
strerror函數(shù)會返回一個指定的錯誤號的錯誤信息的字符串.
4。守護進程的創(chuàng)建
如果你在DOS時代編寫過程序,那么你也許知道在DOS下為了編寫一個常駐內存的程序我們要編寫多少代碼了.相反如果在Linux下編寫一個"常駐內存"的程序卻是很容易的.我們只要幾行代碼就可以做到.實際上由于Linux是多任務操作系統(tǒng),我們就是不編寫代碼也可以把一個程序放到后臺去執(zhí)行的.我們只要在命令后面加上&符號,SHELL就會把我們的程序放到后臺去運行的.這里我們"開發(fā)"一個后臺檢查郵件的程序.這個程序每過一個指定的時間回去檢查我們的郵箱,如果發(fā)現(xiàn)我們有郵件了,會不斷的報警(通過機箱上的小喇叭來發(fā)出聲音).后面有這個函數(shù)的加強版本,加強版本后臺進程的創(chuàng)建思想:首先父進程創(chuàng)建一個子進程.然后子進程殺死父進程(是不是很無情?).信號處理所有的工作由子進程來處理.
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<stdio.h>
#include<errno.h>
#include<fcntl.h>
#include<signal.h>
/*Linux的默任個人的郵箱地址是/var/spool/mail/用戶的登錄名*/
#defineMAIL"/var/spool/mail/hoyt"
/*睡眠10秒鐘*/
#defineSLEEP_TIME10
main(void)
{
pid_tchild;
if((child=fork())==-1)
{
printf("ForkError:%s/n",strerror(errno));
exit(1);
}
elseif(child>0)
while(1);
if(kill(getppid(),SIGTERM)==-1)
{
printf("KillParentError:%s/n",strerror(errno));
exit(1);
}
{
intmailfd;
while(1)
{
if((mailfd=open(MAIL,O_RDONLY))!=-1)
{
fprintf(stderr,"%s","/007");
close(mailfd);
}
sleep(SLEEP_TIME);
}
}
}
你可以在默認的路徑下創(chuàng)建你的郵箱文件,然后測試一下這個程序.當然這個程序還有很多地方要改善的.我們后面會對這個小程序改善的,再看我的改善之前你可以嘗試自己改善一下.比如讓用戶指定郵相的路徑和睡眠時間等等.相信自己可以做到的.動手吧,勇敢的探險者.
好了進程一節(jié)的內容我們就先學到這里了.進程是一個非常重要的概念,許多的程序都會用子進程.創(chuàng)建一個子進程是每一個程序員的基本要求!
3)Linux程序設計入門--文件操作
Linux下文件的操作
前言:
我們在這一節(jié)將要討論linux下文件操作的各個函數(shù).
文件的創(chuàng)建和讀寫
文件的各個屬性
目錄文件的操作
管道文件
1。文件的創(chuàng)建和讀寫
我假設你已經(jīng)知道了標準級的文件操作的各個函數(shù)(fopen,fread,fwrite等等).當然如果你不清楚的話也不要著急.我們討論的系統(tǒng)級的文件操作實際上是為標準級文件操作服務的.
當我們需要打開一個文件進行讀寫操作的時候,我們可以使用系統(tǒng)調用函數(shù)open.使用完成以后我們調用另外一個close函數(shù)進行關閉操作.
#include<fcntl.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
intopen(constchar*pathname,intflags);
intopen(constchar*pathname,intflags,mode_tmode);
intclose(intfd);
open函數(shù)有兩個形式.其中pathname是我們要打開的文件名(包含路徑名稱,缺省是認為在當前路徑下面).flags可以去下面的一個值或者是幾個值的組合.
O_RDONLY:以只讀的方式打開文件.
O_WRONLY:以只寫的方式打開文件.
O_RDWR:以讀寫的方式打開文件.
O_APPEND:以追加的方式打開文件.
O_CREAT:創(chuàng)建一個文件.
O_EXEC:如果使用了O_CREAT而且文件已經(jīng)存在,就會發(fā)生一個錯誤.
O_NOBLOCK:以非阻塞的方式打開一個文件.
O_TRUNC:如果文件已經(jīng)存在,則刪除文件的內容.
前面三個標志只能使用任意的一個.如果使用了O_CREATE標志,那么我們要使用open的第二種形式.還要指定mode標志,用來表示文件的訪問權限.mode可以是以下情況的組合.
-----------------------------------------------------------------
S_IRUSR用戶可以讀S_IWUSR用戶可以寫
S_IXUSR用戶可以執(zhí)行S_IRWXU用戶可以讀寫執(zhí)行
-----------------------------------------------------------------
S_IRGRP組可以讀S_IWGRP組可以寫
S_IXGRP組可以執(zhí)行S_IRWXG組可以讀寫執(zhí)行
-----------------------------------------------------------------
S_IROTH其他人可以讀S_IWOTH其他人可以寫
S_IXOTH其他人可以執(zhí)行S_IRWXO其他人可以讀寫執(zhí)行
-----------------------------------------------------------------
S_ISUID設置用戶執(zhí)行IDS_ISGID設置組的執(zhí)行ID
-----------------------------------------------------------------
我們也可以用數(shù)字來代表各個位的標志.Linux總共用5個數(shù)字來表示文件的各種權限.
00000.第一位表示設置用戶ID.第二位表示設置組ID,第三位表示用戶自己的權限位,第四位表示組的權限,最后一位表示其他人的權限.
每個數(shù)字可以取1(執(zhí)行權限),2(寫權限),4(讀權限),0(什么也沒有)或者是這幾個值的和
..
比如我們要創(chuàng)建一個用戶讀寫執(zhí)行,組沒有權限,其他人讀執(zhí)行的文件.設置用戶ID位那么我們可以使用的模式是--1(設置用戶ID)0(組沒有設置)7(1+2+4)0(沒有權限,使用缺省)
5(1+4)即10705:
open("temp",O_CREAT,10705);
如果我們打開文件成功,open會返回一個文件描述符.我們以后對文件的所有操作就可以對這個文件描述符進行操作了.
當我們操作完成以后,我們要關閉文件了,只要調用close就可以了,其中fd是我們要關閉的文件描述符.
文件打開了以后,我們就要對文件進行讀寫了.我們可以調用函數(shù)read和write進行文件的讀寫.
#include<unistd.h>
ssize_tread(intfd,void*buffer,size_tcount);
ssize_twrite(intfd,constvoid*buffer,size_tcount);
fd是我們要進行讀寫操作的文件描述符,buffer是我們要寫入文件內容或讀出文件內容的內存地址.count是我們要讀寫的字節(jié)數(shù).
對于普通的文件read從指定的文件(fd)中讀取count字節(jié)到buffer緩沖區(qū)中(記住我們必須提供一個足夠大的緩沖區(qū)),同時返回count.
如果read讀到了文件的結尾或者被一個信號所中斷,返回值會小于count.如果是由信號中斷引起返回,而且沒有返回數(shù)據(jù),read會返回-1,且設置errno為EINTR.當程序讀到了文件結尾的時候,read會返回0.
write從buffer中寫count字節(jié)到文件fd中,成功時返回實際所寫的字節(jié)數(shù).
下面我們學習一個實例,這個實例用來拷貝文件.
#include<unistd.h>
#include<fcntl.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include<string.h>
#defineBUFFER_SIZE1024
intmain(intargc,char**argv)
{
intfrom_fd,to_fd;
intbytes_read,bytes_write;
charbuffer[BUFFER_SIZE];
char*ptr;
if(argc!=3)
{
fprintf(stderr,"Usage:%sfromfiletofile/n/a",argv[0]);
exit(1);
}
/*打開源文件*/
if((from_fd=open(argv[1],O_RDONLY))==-1)
{
fprintf(stderr,"Open%sError:%s/n",argv[1],strerror(errno));
exit(1);
}
/*創(chuàng)建目的文件*/
if((to_fd=open(argv[2],O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR))==-1)
{
fprintf(stderr,"Open%sError:%s/n",argv[2],strerror(errno));
exit(1);
}
/*以下代碼是一個經(jīng)典的拷貝文件的代碼*/
while(bytes_read=read(from_fd,buffer,BUFFER_SIZE))
{
/*一個致命的錯誤發(fā)生了*/
if((bytes_read==-1)&&(errno!=EINTR))break;
elseif(bytes_read>0)
{
ptr=buffer;
while(bytes_write=write(to_fd,ptr,bytes_read))
{
/*一個致命錯誤發(fā)生了*/
if((bytes_write==-1)&&(errno!=EINTR))break;
/*寫完了所有讀的字節(jié)*/
elseif(bytes_write==bytes_read)break;
/*只寫了一部分,繼續(xù)寫*/
elseif(bytes_write>0)
{
ptr+=bytes_write;
bytes_read-=bytes_write;
}
}
/*寫的時候發(fā)生的致命錯誤*/
if(bytes_write==-1)break;
}
}
close(from_fd);
close(to_fd);
exit(0);
}
2。文件的各個屬性
文件具有各種各樣的屬性,除了我們上面所知道的文件權限以外,文件還有創(chuàng)建時間,大小等等屬性.
有時侯我們要判斷文件是否可以進行某種操作(讀、寫等等).這個時候我們可以使用access函數(shù).
#include<unistd.h>
intaccess(constchar*pathname,intmode);
pathname:是文件名稱,mode是我們要判斷的屬性.可以取以下值或者是他們的組合.
R_OK文件可以讀,W_OK文件可以寫,X_OK文件可以執(zhí)行,F_OK文件存在.當我們測試成功時,函數(shù)返回0,否則如果有一個條件不符時,返回-1.
如果我們要獲得文件的其他屬性,我們可以使用函數(shù)stat或者fstat.
#include<sys/stat.h>
#include<unistd.h>
intstat(constchar*file_name,structstat*buf);
intfstat(intfiledes,structstat*buf);
structstat{
dev_tst_dev;/*設備*/
ino_tst_ino;/*節(jié)點*/
mode_tst_mode;/*模式*/
nlink_tst_nlink;/*硬連接*/
uid_tst_uid;/*用戶ID*/
gid_tst_gid;/*組ID*/
dev_tst_rdev;/*設備類型*/
off_tst_off;/*文件字節(jié)數(shù)*/
unsignedlongst_blksize;/*塊大小*/
unsignedlongst_blocks;/*塊數(shù)*/
time_tst_atime;/*最后一次訪問時間*/
time_tst_mtime;/*最后一次修改時間*/
time_tst_ctime;/*最后一次改變時間(指屬性)*/
};
stat用來判斷沒有打開的文件,而fstat用來判斷打開的文件.我們使用最多的屬性是st_mode.通過著屬性我們可以判斷給定的文件是一個普通文件還是一個目錄,連接等等.可以使用下面幾個宏來判斷.
S_ISLNK(st_mode):是否是一個連接.S_ISREG是否是一個常規(guī)文件.S_ISDIR是否是一個目錄S_ISCHR是否是一個字符設備.S_ISBLK是否是一個塊設備S_ISFIFO是否是一個FIFO文件.S_ISSOCK是否是一個SOCKET文件.我們會在下面說明如何使用這幾個宏的.
3。目錄文件的操作
在我們編寫程序的時候,有時候會要得到我們當前的工作路徑。C庫函數(shù)提供了getcwd來解決這個問題。
#include<unistd.h>
char*getcwd(char*buffer,size_tsize);
我們提供一個size大小的buffer,getcwd會把我們當前的路徑考到buffer中.如果buffer太小,函數(shù)會返回-1和一個錯誤號.
Linux提供了大量的目錄操作函數(shù),我們學習幾個比較簡單和常用的函數(shù).
#include<dirent.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
intmkdir(constchar*path,mode_tmode);
DIR*opendir(constchar*path);
structdirent*readdir(DIR*dir);
voidrewinddir(DIR*dir);
off_ttelldir(DIR*dir);
voidseekdir(DIR*dir,off_toff);
intclosedir(DIR*dir);
structdirent{
longd_ino;
off_td_off;
unsignedshortd_reclen;
chard_name[NAME_MAX+1];/*文件名稱*/
mkdir很容易就是我們創(chuàng)建一個目錄,opendir打開一個目錄為以后讀做準備.readdir讀一個打開的目錄.rewinddir是用來重讀目錄的和我們學的rewind函數(shù)一樣.closedir是關閉一個目錄.telldir和seekdir類似與ftee和fseek函數(shù).
下面我們開發(fā)一個小程序,這個程序有一個參數(shù).如果這個參數(shù)是一個文件名,我們輸出這個文件的大小和最后修改的時間,如果是一個目錄我們輸出這個目錄下所有文件的大小和修改時間.
#include<unistd.h>
#include<stdio.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<dirent.h>
#include<time.h>
staticintget_file_size_time(constchar*filename)
{
structstatstatbuf;
if(stat(filename,&statbuf)==-1)
{
printf("Getstaton%sError:%s/n",
filename,strerror(errno));
return(-1);
}
if(S_ISDIR(statbuf.st_mode))return(1);
if(S_ISREG(statbuf.st_mode))
printf("%ssize:%ldbytes/tmodifiedat%s",
filename,statbuf.st_size,ctime(&statbuf.st_mtime));
return(0);
}
intmain(intargc,char**argv)
{
DIR*dirp;
structdirent*direntp;
intstats;
if(argc!=2)
{
printf("Usage:%sfilename/n/a",argv[0]);
exit(1);
}
if(((stats=get_file_size_time(argv[1]))==0)||(stats==-1))exit(1);
if((dirp=opendir(argv[1]))==NULL)
{
printf("OpenDirectory%sError:%s/n",
argv[1],strerror(errno));
exit(1);
}
while((direntp=readdir(dirp))!=NULL)
if(get_file_size_time(direntp-<d_name)==-1)break;
closedir(dirp);
exit(1);
}
4。管道文件
Linux提供了許多的過濾和重定向程序,比如morecat
等等.還提供了<>|<<等等重定向操作符.在這些過濾和重定向程序當中,都用到了管
道這種特殊的文件.系統(tǒng)調用pipe可以創(chuàng)建一個管道.
#include<unistd.h>
intpipe(intfildes[2]);
pipe調用可以創(chuàng)建一個管道(通信緩沖區(qū)).當調用成功時,我們可以訪問文件描述符fildes[0],fildes[1].其中fildes[0]是用來讀的文件描述符,而fildes[1]是用來寫的文件描述符.
在實際使用中我們是通過創(chuàng)建一個子進程,然后一個進程寫,一個進程讀來使用的.
關于進程通信的詳細情況請查看進程通信
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/wait.h>
#defineBUFFER255
intmain(intargc,char**argv)
{
charbuffer[BUFFER+1];
intfd[2];
if(argc!=2)
{
fprintf(stderr,"Usage:%sstring/n/a",argv[0]);
exit(1);
}
if(pipe(fd)!=0)
{
fprintf(stderr,"PipeError:%s/n/a",strerror(errno));
exit(1);
}
if(fork()==0)
{
close(fd[0]);
printf("Child[%d]Writetopipe/n/a",getpid());
snprintf(buffer,BUFFER,"%s",argv[1]);
write(fd[1],buffer,strlen(buffer));
printf("Child[%d]Quit/n/a",getpid());
exit(0);
}
else
{
close(fd[1]);
printf("Parent[%d]Readfrompipe/n/a",getpid());
memset(buffer,'/0',BUFFER+1);
read(fd[0],buffer,BUFFER);
printf("Parent[%d]Read:%s/n",getpid(),buffer);
exit(1);
}
}
為了實現(xiàn)重定向操作,我們需要調用另外一個函數(shù)dup2.
#include<unistd.h>
intdup2(intoldfd,intnewfd);
dup2將用oldfd文件描述符來代替newfd文件描述符,同時關閉newfd文件描述符.也就是說,所有向newfd操作都轉到oldfd上面.下面我們學習一個例子,這個例子將標準輸出重定向到一個文件.
#include<unistd.h>
#include<stdio.h>
#include<errno.h>
#include<fcntl.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#defineBUFFER_SIZE1024
intmain(intargc,char**argv)
{
intfd;
charbuffer[BUFFER_SIZE];
if(argc!=2)
{
fprintf(stderr,"Usage:%soutfilename/n/a",argv[0]);
exit(1);
}
if((fd=open(argv[1],O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR))==-1)
{
fprintf(stderr,"Open%sError:%s/n/a",argv[1],strerror(errno));
exit(1);
}
if(dup2(fd,STDOUT_FILENO)==-1)
{
fprintf(stderr,"RedirectStandardOutError:%s/n/a",strerror(errno));
exit(1);
}
fprintf(stderr,"Now,pleaseinputstring");
fprintf(stderr,"(ToquituseCTRL+D)/n");
while(1)
{
fgets(buffer,BUFFER_SIZE,stdin);
if(feof(stdin))break;
write(STDOUT_FILENO,buffer,strlen(buffer));
}
exit(0);
}
好了,文件一章我們就暫時先討論到這里,學習好了文件的操作我們其實已經(jīng)可以寫出一些比較有用的程序了.我們可以編寫一個實現(xiàn)例如dir,mkdir,cp,mv等等常用的文件操作命令了.
想不想自己寫幾個試一試呢?
4)程序設計入門--時間概念
前言:Linux下的時間概念
這一章我們學習Linux的時間表示和計算函數(shù)時間的表示時間的測量計時器的使用
1。時間表示在程序當中,我們經(jīng)常要輸出系統(tǒng)當前的時間,比如我們使用date命令的輸出結果.這個時候我們可以使用下面兩個函數(shù)
#include<time.h>
time_ttime(time_t*tloc);
char*ctime(consttime_t*clock);
time函數(shù)返回從1970年1月1日0點以來的秒數(shù).存儲在time_t結構之中.不過這個函數(shù)的返回值對于我們來說沒有什么實際意義.這個時候我們使用第二個函數(shù)將秒數(shù)轉化為字符串
..這個函數(shù)的返回類型是固定的:一個可能值為.ThuDec714:58:592000這個字符串的長度是固定的為262。時間的測量有時候我們要計算程序執(zhí)行的時間.比如我們要對算法進行時間分析
..這個時候可以使用下面這個函數(shù).
#include<sys/time.h>
intgettimeofday(structtimeval*tv,structtimezone*tz);
struttimeval{
longtv_sec;/*秒數(shù)*/
longtv_usec;/*微秒數(shù)*/
};
gettimeofday將時間保存在結構tv之中.tz一般我們使用NULL來代替.
#include<sys/time.h<
#include<stdio.h<
#include<math.h<
voidfunction()
{
unsignedinti,j;
doubley;
for(i=0;i<1000;i++)
for(j=0;j<1000;j++)
y=sin((double)i);
}
main()
{
structtimevaltpstart,tpend;
floattimeuse;
gettimeofday(&tpstart,NULL);
function();
gettimeofday(&tpend,NULL);
timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+
tpend.tv_usec-tpstart.tv_usec;
timeuse/=1000000;
printf("UsedTime:%f/n",timeuse);
exit(0);
}
這個程序輸出函數(shù)的執(zhí)行時間,我們可以使用這個來進行系統(tǒng)性能的測試,或者是函數(shù)算法的效率分析.在我機器上的一個輸出結果是:UsedTime:0.556070
3。計時器的使用Linux操作系統(tǒng)為每一個進程提供了3個內部間隔計時器.
ITIMER_REAL:減少實際時間.到時的時候發(fā)出SIGALRM信號.
ITIMER_VIRTUAL:減少有效時間(進程執(zhí)行的時間).產(chǎn)生SIGVTALRM信號.
ITIMER_PROF:減少進程的有效時間和系統(tǒng)時間(為進程調度用的時間).這個經(jīng)常和上面一個使用用來計算系統(tǒng)內核時間和用戶時間.產(chǎn)生SIGPROF信號.
具體的操作函數(shù)是:
#include<sys/time.h>
intgetitimer(intwhich,structitimerval*value);
intsetitimer(intwhich,structitimerval*newval,structitimerval*oldval);
structitimerval{
structtimevalit_interval;
structtimevalit_value;
}
getitimer函數(shù)得到間隔計時器的時間值.保存在value中setitimer函數(shù)設置間隔計時器的時間值為newval.并將舊值保存在oldval中.which表示使用三個計時器中的哪一個.itimerval結構中的it_value是減少的時間,當這個值為0的時候就發(fā)出相應的信號了.然后設置為it_interval值.
#include<sys/time.h>
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<string.h>
#definePROMPT"時間已經(jīng)過去了兩秒鐘/n/a"
char*prompt=PROMPT;
unsignedintlen;
voidprompt_info(intsigno)
{
write(STDERR_FILENO,prompt,len);
}
voidinit_sigaction(void)
{
structsigactionact;
act.sa_handler=prompt_info;
act.sa_flags=0;
sigemptyset(&act.sa_mask);//清空此信號集
sigaction(SIGPROF,&act,NULL);
}
voidinit_time()
{
structitimervalvalue;
value.it_value.tv_sec=2;
value.it_value.tv_usec=0;
value.it_interval=value.it_value;
setitimer(ITIMER_PROF,&value,NULL);
}
intmain()
{
len=strlen(prompt);
init_sigaction();
init_time();
while(1);
exit(0);
}
這個程序每執(zhí)行兩秒中之后會輸出一個提示.
5)Linux程序設計入門--信號處理
Linux下的信號事件
前言:這一章我們討論一下Linux下的信號處理函數(shù).
Linux下的信號處理函數(shù):
信號的產(chǎn)生
信號的處理
其它信號函數(shù)
一個實例
1。信號的產(chǎn)生
Linux下的信號可以類比于DOS下的INT或者是Windows下的事件.在有一個信號發(fā)生時候相應的信號就會發(fā)送給相應的進程.在Linux下的信號有以下幾個.我們使用kill-l命令可以得到以下的輸出結果:
1)SIGHUP2)SIGINT3)SIGQUIT4)SIGILL
5)SIGTRAP6)SIGABRT7)SIGBUS8)SIGFPE
9)SIGKILL10)SIGUSR111)SIGSEGV12)SIGUSR2
13)SIGPIPE14)SIGALRM15)SIGTERM17)SIGCHLD
18)SIGCONT19)SIGSTOP20)SIGTSTP21)SIGTTIN
22)SIGTTOU23)SIGURG24)SIGXCPU25)SIGXFSZ
26)SIGVTALRM27)SIGPROF28)SIGWINCH29)SIGIO
30)SIGPWR
關于這些信號的詳細解釋請查看man7signal的輸出結果.信號事件的發(fā)生有兩個來源:一個是硬件的原因(比如我們按下了鍵盤),一個是軟件的原因(比如我們使用系統(tǒng)函數(shù)或者是命令發(fā)出信號).最常用的四個發(fā)出信號的系統(tǒng)函數(shù)是kill,raise,alarm和setitimer函數(shù).setitimer函數(shù)我們在計時器的使用那一章再學習.
#include<sys/types.h>
#include<signal.h>
#include<unistd.h>
intkill(pid_tpid,intsig);
intraise(intsig);
unisignedintalarm(unsignedintseconds);
kill系統(tǒng)調用負責向進程發(fā)送信號sig.
如果pid是正數(shù),那么向信號sig被發(fā)送到進程pid.
如果pid等于0,那么信號sig被發(fā)送到所以和pid進程在同一個進程組的進程
如果pid等于-1,那么信號發(fā)給所有的進程表中的進程,除了最大的哪個進程號.
如果pid小于0,將信號傳給進程組識別碼為pid絕對值的所有進程.
我們用最多的是第一個情況.還記得我們在守護進程那一節(jié)的例子嗎?我們那個時候用這個函數(shù)殺死了父進程守護進程的創(chuàng)建
raise系統(tǒng)調用向自己發(fā)送一個sig信號.我們可以用上面那個函數(shù)來實現(xiàn)這個功能的.
alarm函數(shù)和時間有點關系了,這個函數(shù)可以在seconds秒后向自己發(fā)送一個SIGALRM信號
..下面這個函數(shù)會有什么結果呢?
#include<unistd.h>
main()
{
unsignedinti;
alarm(1);
for(i=0;1;i++)
printf("I=%d",i);
}
SIGALRM的缺省操作是結束進程,所以程序在1秒之后結束,你可以看看你的最后I值為多少,來比較一下大家的系統(tǒng)性能差異(我的是2232).
2。信號操作有時候我們希望進程正確的執(zhí)行,而不想進程受到信號的影響,比如我們希望上面那個程序在1秒鐘之后不結束.這個時候我們就要進行信號的操作了.
信號操作最常用的方法是信號屏蔽.信號屏蔽要用到下面的幾個函數(shù).
#include<signal.h>
intsigemptyset(sigset_t*set);
intsigfillset(sigset_t*set);
intsigaddset(sigset_t*set,intsigno);
intsigdelset(sigset_t*set,intsigno);
intsigismember(sigset_t*set,intsigno);
intsigprocmask(inthow,constsigset_t*set,sigset_t*oset);
sigemptyset函數(shù)初始化信號集合set,將set設置為空.sigfillset也初始化信號集合,只是將信號集合設置為所有信號的集合.sigaddset將信號signo加入到信號集合之中,sigdelset將信號從信號集合中刪除.sigismember查詢信號是否在信號集合之中.sigprocmask是最為關鍵的一個函數(shù).在使用之前要先設置好信號集合set.這個函數(shù)的作用是將指定的信號集合set加入到進程的信號阻塞集合之中去,如果提供了oset那么當前的進程信號阻塞集合將會保存在oset里面.參數(shù)how決定函數(shù)的操作方式.
SIG_BLOCK:增加一個信號集合到當前進程的阻塞集合之中.
SIG_UNBLOCK:從當前的阻塞集合之中刪除一個信號集合.
SIG_SETMASK:將當前的信號集合設置為信號阻塞集合.
以一個實例來解釋使用這幾個函數(shù).
#include<signal.h>
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
intmain(intargc,char**argv)
{
doubley;
sigset_tintmask;
inti,repeat_factor;
if(argc!=2)
{
fprintf(stderr,"Usage:%srepeat_factor/n/a",argv[0]);
exit(1);
}
if((repeat_factor=atoi(argv[1]))<1)repeat_factor=10;
sigemptyset(&intmask);/*將信號集合設置為空*/
sigaddset(&intmask,SIGINT);/*加入中斷Ctrl+C信號*/
while(1)
{
/*阻塞信號,我們不希望保存原來的集合所以參數(shù)為NULL*/
sigprocmask(SIG_BLOCK,&intmask,NULL);
fprintf(stderr,"SIGINTsignalblocked/n");
for(i=0;i<repeat_factor;i++)y=sin((double)i);
fprintf(stderr,"Blockedcalculationisfinished/n");
/*取消阻塞*/
sigprocmask(SIG_UNBLOCK,&intmask,NULL);
fprintf(stderr,"SIGINTsignalunblocked/n");
for(i=0;i<repeat_factor;i++)y=sin((double)i);
fprintf(stderr,"Unblockedcalculationisfinished/n");
}
exit(0);
}
程序在運行的時候我們要使用Ctrl+C來結束.如果我們在第一計算的時候發(fā)出SIGINT信號,由于信號已經(jīng)屏蔽了,所以程序沒有反映.只有到信號被取消阻塞的時候程序才會結束.注意我們只要發(fā)出一次SIGINT信號就可以了,因為信號屏蔽只是將信號加入到信號阻塞集合之中,并沒有丟棄這個信號.一旦信號屏蔽取消了,這個信號就會發(fā)生作用.
有時候我們希望對信號作出及時的反映的,比如當擁護按下Ctrl+C時,我們不想什么事情也不做,我們想告訴用戶你的這個操作不好,請不要重試,而不是什么反映也沒有的.這個時候我們要用到sigaction函數(shù).
#include<signal.h>
intsigaction(intsigno,conststructsigaction*act,structsigaction*oact);
structsigaction{
void(*sa_handler)(intsigno);
void(*sa_sigaction)(intsiginfo_t*info,void
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 六盤水職業(yè)技術學院《典型零件的工藝設計》2023-2024學年第一學期期末試卷
- 金肯職業(yè)技術學院《微機原理含實驗》2023-2024學年第一學期期末試卷
- 新蘇教版一年級下冊數(shù)學第1單元第3課時《8、7加幾》作業(yè)
- 懷化學院《影視創(chuàng)作前沿技術》2023-2024學年第一學期期末試卷
- 湖北理工學院《人力資源管理咨詢與診斷》2023-2024學年第一學期期末試卷
- 資陽口腔職業(yè)學院《測試與傳感器技術》2023-2024學年第一學期期末試卷
- 小學黨員聯(lián)系群眾、服務群眾制度
- 長沙學院《材料加工過程多尺度模擬》2023-2024學年第一學期期末試卷
- 寒露節(jié)氣策劃講座模板
- 職業(yè)導論-房地產(chǎn)經(jīng)紀人《職業(yè)導論》名師預測卷3
- 藝術品捐贈協(xié)議
- 網(wǎng)絡安全系統(tǒng)運維方案
- 2024年標準溝渠回填工程承包協(xié)議版B版
- 2024年專用:物業(yè)安全管理協(xié)議3篇
- 【公開課】同一直線上二力的合成+課件+2024-2025學年+人教版(2024)初中物理八年級下冊+
- 《政府采購業(yè)務培訓》課件
- 《醫(yī)療器械召回管理辦法》培訓2024
- 網(wǎng)絡安全培訓內容課件
- 通信線路維護安全培訓
- 專業(yè)微信小程序開發(fā)協(xié)議范例版
- 高職組全國職業(yè)院校技能大賽(嬰幼兒照護賽項)備賽試題庫(含答案)
評論
0/150
提交評論