UNIX环境编程
linux函數(shù)分析查詢工具
1.優(yōu)先推薦linux 中man命令
2.一個不錯的中文Linux手冊:http://cpp.ezbty.org/manpage
3.在線查英文Man手冊:
http://www.kernel.org/doc/man-pages/
http://man7.org/linux/man-pages/dir_all_alphabetic.html
http://linux.about.com/od/commands/l/blcmdl.htm
http://linux.die.net/man/
http://www.linuxmanpages.com/
man 命令
| 部分 | 內(nèi)容 |
|---|---|
| man1 | 一般命令。這個部分中的命令通常不需要超級用戶(即管理員)特權(quán)。ls、cat 和 passwd 放在這里,還有 shell。例如,請試試 man bash。 |
| man2 | 用來訪問 UNIX 內(nèi)核提供的服務(wù)的系統(tǒng)調(diào)用或函數(shù)。例如 fork 系統(tǒng),它從一個現(xiàn)有的進程生成一個新進程。輸入 man fork 顯示它的手冊頁。使用系統(tǒng)軟件的程序員常常參考這個部分。 |
| man3 | C 庫函數(shù)。許多軟件包提供功能豐富的代碼庫,讓開發(fā)人員可以創(chuàng)建新軟件來補充現(xiàn)有的特性或開發(fā)全新的特性。每個庫通常有一個手冊頁;一些庫(比如系統(tǒng)的 libc)太大了,所以各個函數(shù)或一組相關(guān)函數(shù)有單獨的文檔。 |
| man4 | 特殊文件,比如設(shè)備和驅(qū)動程序。 |
| man5 | 文件格式。UNIX 幾乎完全使用文本配置文件定制系統(tǒng)的操作。有大量配置文件,包括網(wǎng)絡(luò)服務(wù)的列表 (/etc/services) 和可用的 shell 列表 (/etc/shells) 等等。 |
| man6 | 游戲和屏幕保護程序。 |
| man7 | 雜類文件。這是一個包羅萬象的類別。在傳統(tǒng)的系統(tǒng)上,可以了解 glob 操作符、正則表達式等方面的信息。 |
| man8 | 系統(tǒng)管理命令,超級用戶很可能要使用它們。 |
在某些情況下,不同部分中的組件可能名稱相同。這種現(xiàn)象很常見,尤其是在一個軟件包有多個部分的情況下。例如,第一部分中有 crontab 命令,它提交要調(diào)度的作業(yè)。同時,第五部分中有 crontab 文件格式,它描述要運行的作業(yè)。
為了區(qū)分不同部分中的同名組件,應(yīng)該在第一個參數(shù)中提供部分號:
$ man 1 crontab $ man 5 crontab |
前一個命令顯示 crontab 命令的手冊頁;后一個命令顯示 crontab 文件格式。如果一個軟件在多個部分中存在,而您沒有指定部分號,man 就會顯示在編號最低的部分中找到的匹配。
使用-k的man命令可根據(jù)關(guān)鍵字搜索
#man -k fork
看第一行就是我們需要的信息,加上小節(jié)號
#man 2 fork
從這里我們知道在unistd.h中有fork
該頭文件在/usr/include中
#/usr/include
#vim? unistd.h
庫函數(shù)和系統(tǒng)調(diào)用的區(qū)別
庫函數(shù)是高層的,完全運行在用戶空間,為程序員提供調(diào)用真正的在幕后完成實際事務(wù)的系統(tǒng)調(diào)用的更方便的接口。系統(tǒng)調(diào)用在內(nèi)核態(tài)運行并且由內(nèi)核自己提供。標準C庫函數(shù)printf()可以被看做是一個通用的輸出語句,但它實際做的是將數(shù)據(jù)轉(zhuǎn)化為符合格式的字符串并且調(diào)用系統(tǒng)調(diào)用 write()輸出這些字符串。
是否想看一看printf()究竟使用了哪些系統(tǒng)調(diào)用? 這很容易,編譯下面的代碼。
#include <stdio.h>
int main(void)
{
printf("hello");
return 0;
}
使用命令gcc -Wall -o hello hello.c編譯或者直接cc編譯a.out文件。
用命令
#strace ./hello
或者
#strace ./a.out
跟蹤該可執(zhí)行文件。
每一行都和一個系統(tǒng)調(diào)用相對應(yīng)。 strace是一個非常有用的程序,它可以告訴你程序使用了哪些系統(tǒng)調(diào)用和這些系統(tǒng)調(diào)用的參數(shù)、返回值。 這是一個極有價值的查看程序在干什么的工具。在輸出的末尾,你應(yīng)該看到這樣類似的一行 write(1, "hello", 5hello)。這就是我們要找的。藏在面具printf() 的真實面目。既然絕大多數(shù)人使用庫函數(shù)來對文件I/O進行操作(像 fopen, fputs, fclose)。 你可以查看man說明的第二部分使用命令man 2 write 。man說明的第二部分專門介紹系統(tǒng)調(diào)用(像kill()和read())。 man說明的第三部分則專門介紹你可能更熟悉的庫函數(shù)(像cosh()和random())。
1.getenv
NAME ? ? ? ??
getenv, secure_getenv - get an environment variable
SYNOPSIS ? ? ? ??
#include <stdlib.h>char *getenv(const char *name);char *secure_getenv(const char *name);Feature Test Macro Requirements for glibc (see feature_test_macros(7)):secure_getenv(): _GNU_SOURCE
http://man7.org/linux/man-pages/man3/getenv.3.html
函數(shù)說明 getenv()用來取得參數(shù)name環(huán)境變量的內(nèi)容。參數(shù)name為環(huán)境變量的名稱,如果該變量存在則會返回指向該內(nèi)容的指針。環(huán)境變量的格式為name=value。
返回值:執(zhí)行成功則返回指向該內(nèi)容的指針,找不到符合的環(huán)境變量名稱則返回NULL。
2.putenv
NAME ? ? ? ??
putenv - change or add an environment variable
SYNOPSIS ? ? ? ??
#include <stdlib.h>int putenv(char *string);Feature Test Macro Requirements for glibc (see feature_test_macros(7)):putenv(): _SVID_SOURCE || _XOPEN_SOURCEhttp://man7.org/linux/man-pages/man3/putenv.3.html
函數(shù)說明:putenv()用來改變或增加環(huán)境變量的內(nèi)容。參數(shù)string的格式為name=value,如果該環(huán)境變量原先存在,則變量內(nèi)容會依參數(shù)string改變,否則此參數(shù)內(nèi)容會成為新的環(huán)境變量。
返回值:執(zhí)行成功則返回0,有錯誤發(fā)生則返回-1。
錯誤代碼:ENOMEM 內(nèi)存不足,無法配置新的環(huán)境變量空間。
3.setenv
NAME ? ? ? ??
setenv - change or add an environment variable
SYNOPSIS ? ? ? ??
#include <stdlib.h>int setenv(const char *name, const char *value, int overwrite);int unsetenv(const char *name);Feature Test Macro Requirements for glibc (see feature_test_macros(7)):setenv(), unsetenv():_BSD_SOURCE || _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600http://man7.org/linux/man-pages/man3/setenv.3.html 函數(shù)說明: setenv()用來改變或增加環(huán)境變量的內(nèi)容。
參數(shù) name為環(huán)境變量名稱字符串。
參數(shù) value則為變量內(nèi)容。
參數(shù) overwrite用來決定是否要改變已存在的環(huán)境變量。如果overwrite不為0,則改變環(huán)境變量原有內(nèi)容,原有內(nèi)容會被改為參數(shù)value所指的變量內(nèi)容。如果overwrite為0,且該環(huán)境變量已有內(nèi)容,則參數(shù)value會被忽略。
返回值: 執(zhí)行成功則返回0,有錯誤發(fā)生時返回-1。
錯誤代碼: ENOMEM 內(nèi)存不足,無法配置新的環(huán)境變量空間
#include <stdio.h>
#include <stdlib.h>
main()
{
char *p;
if((p = getenv("USER")))
printf("USER=%s\n",p);
putenv("USER=root");
printf("USER=%s\n",getenv("USER"));
setenv("USER","test",1);
printf("USER=%s\n",getenv("USER"));
unsetenv("USER");
printf("USER=%s\n",getenv("USER"));
}
輸出:
USER=root
USER=test
USER=test
USER=(null)
4.printf的buffer緩沖
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main(void)
{int i;for(i=0; i<2; i++){fork();printf("-");}return 0;
}
注意:輸出8個-,而不是6個-
1.fork()系統(tǒng)調(diào)用是Unix下以自身進程創(chuàng)建子進程的系統(tǒng)調(diào)用,一次調(diào)用,兩次返回,如果返回是0,則是子進程,如果返回值>0,則是父進程(返回值是子進程的pid),這是眾為周知的。
2.還有一個很重要的東西是,在fork()的調(diào)用處,整個父進程空間會原模原樣地復(fù)制到子進程中,包括指令,變量值,程序調(diào)用棧,環(huán)境變量,緩沖區(qū),等等。
因為printf(“-”);語句有buffer,所以,對于上述程序,printf(“-”);把“-”放到了緩存中,并沒有真正的輸出。在fork的時候,緩存被復(fù)制到了子進程空間,所以,就多了兩個,就成了8個,而不是6個。
Unix下的設(shè)備有“塊設(shè)備”和“字符設(shè)備”的概念,所謂塊設(shè)備,就是以一塊一塊的數(shù)據(jù)存取的設(shè)備,字符設(shè)備是一次存取一個字符的設(shè)備。磁盤、內(nèi)存都是塊設(shè)備,字符設(shè)備如鍵盤和串口。塊設(shè)備一般都有緩存,而字符設(shè)備一般都沒有緩存。
對于上面的問題,我們?nèi)绻薷囊幌律厦娴膒rintf的那條語句為:printf("-\n");
或是
printf("-");fflush(stdout);
就沒有問題了(就是6個“-”了),因為程序遇到“\n”,或是EOF,或是緩中區(qū)滿,或是文件描述符關(guān)閉,或是主動flush,或是程序退出,就會把數(shù)據(jù)刷出緩沖區(qū)。需要注意的是,標準輸出是行緩沖,所以遇到“\n”的時候會刷出緩沖區(qū),但對于磁盤這個塊設(shè)備來說,“\n”并不會引起緩沖區(qū)刷出的動作,那是全緩沖,你可以使用setvbuf來設(shè)置緩沖區(qū)大小,或是用fflush刷緩存。
參考:http://coolshell.cn/articles/7965.html
fflush用于清空緩沖流,雖然一般感覺不到,但是默認printf是緩沖輸出的。
fflush(stdout),使stdout清空,就會立刻輸出所有在緩沖區(qū)的內(nèi)容。
fflush(stdout)這個例子可能不太明顯,但對stdin很明顯。
如下語句:
int a,c;
scanf("%d",&a);
getchar();
輸入:
12(回車)
那么 a=12 ,c= '\n'
而:
int a,c;
scanf("%d",&a);
fflush(stdin);
getchar();
輸入:
12(回車)
那么a=12, c暫時未得到輸入值,還需要再輸入c,因為getchar也是緩沖輸入,'\n'本還在緩沖區(qū),但是被清空了。
另外fflush不能作用于重定向輸入流。
5.linux驅(qū)動程序中字符設(shè)備和塊設(shè)備的三點區(qū)別
1.字符設(shè)備只能以字節(jié)為最小單位訪問,而塊設(shè)備以塊為單位訪問,例如512字節(jié),1024字節(jié)等
2.塊設(shè)備可以隨機訪問,但是字符設(shè)備不可以
3.字符和塊沒有訪問量大小的限制,塊也可以以字節(jié)為單位來訪問
參考:http://www.cnblogs.com/qlee/archive/2011/07/27/2118406.html總結(jié)
- 上一篇: 花生焖猪蹄怎么做好吃,花生焖猪蹄的家常做
- 下一篇: 《梦仙》第三十六句是什么