1. 程式人生 > >UNIX環境高階程式設計(3) 第二章

UNIX環境高階程式設計(3) 第二章

2.2UNIX標準化

2.2.1 ISO C

國際標準化組織(International Organization for Standardization,ISO)

國際電子技術委員會(International Electrotechnical Commission,IEC)

ISO C標準的意圖是提供C程式的可移植性,使其能適合於大量不同的作業系統,而不只是UNIX系統。此標準不僅定義了C程式設計語言的語法和語義,還定義了其標準庫。因為所有現今的UNIX系統都提供C標準中定義的庫例程,所以該標準庫是很重要的

按照該標準定義的各個標頭檔案,可將ISO C庫分成24個區。

ISO C標準定義的標頭檔案:

<asser.h>:驗證程式斷言
<complex.h>:支援複數算術運算
<ctype.h>:字元型別
<errno.h>:出錯碼
<fenv.h>:浮點環境
<float.h>:浮點常量
<inttypes.h>:整型格式轉換
<iso646.h>:替代關係操作符巨集
<limits.h>:實現常量
<locale.h>:區域性類別
<math.h>:數字常量
<setjmp.h>:非區域性goto
<signal.h>:訊號
<stdarg.h
>
:可變引數表 <stdbool.h>:布林型別的值 <stddef.h>:標準定義 <stdint.h>整型 <stdio.h>標準I/O庫 <stdlib.h>實用程式函式 <string.h>字串操作 <tgmath.h>:通用型別數學巨集 <time.h>:時間和日期 <wchar.h>:擴充套件的多位元組和寬位元組支援 <wctype.h>:寬字元分類和對映支援

2.2.2 IEEE POSIX

POSIX是一些列由IEEE(Institute of Electrical and Electronics Engineers,電氣與電子工程師協會)制定的標準。POSIX指的是可移植的作業系統介面。他原來只是IEEE標準1003.1-1988(作業系統介面),後來擴充套件稱包括很多標記為1003的標準及標準草案,包括shell和實用程式(1003.2)

1003.1作業系統介面標準,該標準的目的是提高應用程式在各種UNIX系統環境的可移植性。它定義了“依從POSIX的”作業系統必須提供的各種服務。該標準已被大多數計算機制造商採用。雖然1003.1標準是以UNIX作業系統為基礎的,但是它並不限於UNIX和類UNIX的系統。確實,有些供應專有作業系統的製造商也聲稱這些系統將依從POSIX(同時還保有他們的所有專有功能)

由於1003.1標準定義了一個介面而不是一種實現,所以並不區分系統呼叫和庫函式。標準中的所有例程都稱為函式

POSIX標準定義的必須的標頭檔案(26項)

<dirent.h>      ----------------------   目錄項
<fcntl.h>       ----------------------   檔案控制
<fnmatch.h>     ----------------------   檔名匹配型別
<glob.h>        ----------------------   路徑名模式匹配型別
<grp.h>         ----------------------   組檔案
<netdb.h>       ----------------------   網路資料庫操作
<pwd.h>         ----------------------   口令檔案
<regex.h>       ----------------------   正則表示式
<tar.h>         ----------------------   tar歸檔值
<termios.h>     ----------------------   終端I/O
<unistd.h>      ----------------------   符號常量
<utime.h>       ----------------------   檔案時間
<wordexp.h>     ----------------------   字擴充套件型別
<arpa/inet.h>   ----------------------   Internet定義
<net/if..h>     ----------------------   套接字本地介面
<netinet/in.h>  ----------------------   Internet地址族
<netinet/tcp.h> ----------------------   傳輸控制協議定義
<sys/mman.h>    ----------------------   記憶體管理宣告
<sys/select.h>  ----------------------   select函式
<sys/socket.h>  ----------------------   套接字介面
<sys/stat.h>    ----------------------   檔案狀態
<sys/times.h>   ----------------------   程序時間
<sys/types.h>   ----------------------   基本系統資料型別
<sys/un.h>      ----------------------   UNIX域套接字定義
<sys/utsname.h> ----------------------系統名
<sys/wait.h>    ----------------------   程序控制

POSIX標準定義的XSI擴充套件標頭檔案(26項)

<cpio.h>        ----------------------   cpio歸檔值
<dlfcn.h>       ----------------------   動態連結
<fmtmsg.h>      ----------------------   訊息顯示結構
<ftw.h>         ----------------------   檔案樹漫遊
<iconv.h>       ----------------------   程式碼集轉換實用程式
<langinfo.h>    ----------------------   語言資訊常量
<libgen.h>      ----------------------   模式匹配函式定義
<monetary.h>    ----------------------   貨幣型別
<ndbm.h>        ----------------------   資料庫操作
<nl_types.h>    ----------------------   訊息類別
<poll.h>        ----------------------   輪詢函式
<search.h>      ----------------------   搜尋表
<strings.h>     ----------------------   字串操作
<syslog.h>      ----------------------   系統出錯日誌記錄
<ucontext.h>    ----------------------   使用者上下文
<ulimit.h>      ----------------------   使用者限制
<utmpx.h>       ----------------------   使用者帳戶資料庫
<sys/ipc.h>     ----------------------   IPC
<sys/msg.h>     ----------------------   訊息佇列
<sys/resource.h>-------------------   資源操作
<sys/sem.h>     ----------------------   訊號量
<sys/shm.h>     ----------------------   共享儲存
<sys/statvfs.h> ----------------------   檔案系統資訊
<sys/time.h>    ----------------------   時間型別
<sys/timeb.h>   ----------------------   附加的日期和時間定義
<sys/uio.h>     ----------------------   向量I/O操作

POSIX標準定義的可選標頭檔案(8項)

<aio.h>         ----------------------   非同步I/O
<mqueue.h>      ----------------------   訊息佇列
<pthread.h>     ----------------------   執行緒
<sched.h>       ----------------------   執行排程
<semaphore.h>   ---------------------   訊號量
<spawn.h>       ----------------------   實時spawn介面
<stropts.h>     ----------------------   XSI STREAMS介面
<trace.h>       ----------------------   時間跟蹤  

POSIX.1沒有包括超級使用者這樣的概念,代之以規定某些操作要求“適當的特權”,

2.2.3 Single UNIX Specification

Single UNIX Specification是POSIX.1標準的超集,定義了一些附加的介面,這些介面擴充套件了基本的POSIX.1規範的功能。相應的系統介面全集被稱為X/Open系統介面(XSI,X/Open System Interface) ,XSI還定義了實現必須支援的POSIX.1的哪些可選部分才能認為是遵循XSI的。它們包括檔案同步,儲存對映檔案,儲存保護及執行緒介面。只有遵循XSI的實現才能稱為UNIX作業系統。

2.2.4 FIPS

FIPS的含義是聯邦資訊處理標準(Federal Information Procesing Standard).

POSIX.1 FIPS的影響是:它要球任何希望向美國政府銷售POSIX.1相容的計算機系統的廠商應支援POSIX.1的某些可選功能。因為POSIX.1 FIPS的影響鄭逐步減退,所以在本書中我們將不再進一步考慮它

2.3 UNIX系統實現

SVR4

4.4BSD

FreeBSD

Linux

Mac OS X

Solaris

2.5限制

編譯時限制可在標頭檔案中定義,程式在編譯時可以包含這些標頭檔案。但是,執行時限制則要求程序呼叫一個函式以獲得此種限制值

另外,某些限制在一個給定的實現中可能是固定的(因此可以靜態地在一個頭檔案中定義),而在另一個實現上則可能變化的(需要有一個執行時函式呼叫)

為解決這類問題,提供以下三種限制:

1.編譯時限制(標頭檔案)

2.不與檔案或目錄相關聯的執行時限制(sysconf函式)

3.與檔案或目錄相關聯的執行時限制(pathconf和fpathconf函式)

使事情變得更加複雜的是,如果一個特定的執行時限制在一個給定的系統上並不改變,則可將其靜態地定義在一個頭檔案中,但是,如果沒有將其定義在標頭檔案中,則應用程式必須呼叫三個conf函式中的一個,以確定其執行的值

2.5.1 ISO C限制

ISO C定義的限制都是編譯時限制。

2.5.2 POSIX限制

POSIX.1定義了很多涉及作業系統實現限制的常量,不幸的是,這是POSIX.1中最令人迷惑不解的部分之一

1.不變的最小值

2.不變值:SSIZE_MAX

3.執行時可以增加的值:CHARCLASS_NAME_MAX,COLL_WEIGHTS_MAX,LINE_MAX,NGROUPS_MAX以及RE_DUP_MAX

4.執行時不變的值(可能不確定):ARG_MAX,CHILD_MAX,HOST_NAME_MAX,LOGIN_NAME_MAX,OPEN_MAX,PAGESIZE,RE_DUP_MAX,STREAN_MAXS,SYMLOOP_MAX,TTY_NAME_MAX以及TZNAME_MAX

5.路徑名可變值(可能不確定):FILESIZEBITS,LINK_MAX,MAX_CANON,MAX_INPUT,NAME_MAX,PATH_MAX,PIPE_BUF以及SYMLINK_MAX

2.5.3 XSI限制

XSI還定義了處理實現限制的下面幾個常量:

1.不變最小值:NL_ARGMAX,NL_LANGMAX,NL_MSGMAX,NL_NMAX,NL_SETMAX,NL_TEXTMAX,NZERO,_XOPEN_IOV_MAX,_XOPEN_NAME_MAX,_XOPEN_PATH_MAX

2.數值限制:LONG_BITWORD_BIT

3.執行時不變值(可能不確定):ATEXIT_MAX,IOV_MAX以及PAGE_SIZE

2.5.4 sysconf,pathconf和fpathconf函式

執行時限制可通過呼叫下面三個函式中的一個而取得

#include <unistd.h>
long sysconf(int name);
long pathconf(const char *pathname,int name);
long fpathconf(int filedes,int name);

SC開始的常量用作標識執行時限制的sysconf引數。以PC開始的常量用作標識執行時限制的pathconf或fpathconf引數

對於pathconf的引數pathname以及fpathconf的引數filedes有一些限制。如果不滿足其中任何一個限制,則結果是未定義的

1._PC_MAX_CANON_PC_MAX_INPUT所引用的檔案必須是終端檔案

2._PC_LINK_MAX所引用的檔案可以是檔案或目錄。如果是目錄,則返回值用於目錄本身(而不是用於目錄內的檔名項)

3._PC_FILESIZEBITS_PC_NAME_MAX所引用的檔案必須是目錄,返回值用於該目錄中的檔名

4._PC_PATH_MAX引用的檔案必須是目錄。當所指定的目錄是工作目錄時,返回值是相對路徑名的最大長度(

5._PA_PIPE_BUF所引用的檔案必須是管道,FIFO或目錄。在管道或FIFO情況下,返回值是對所引用的管道或FIFO的限制值。對於目錄,返回值是對該目錄中建立的任意FIFO的限 制值

6._PC_SYMLINK_MAX所引用的檔案必須是目錄。返回值是該目錄中符號連結可能包含的字串的最大長度

程式清單2_2 列印所有可能的sysconf和pathconf的值

#include"apue.h"
#include<errno.h>
#include<limits.h>
static void pr_sysconf(char*,int);
static void pr_pathconf(char*,char*,int);
int main(int argc,char *argv[])
{
    if(argc!=2)
    err_quit("usage:a.out<dirname>");
#ifdef ARG_MAX
    printf("ARG_MAX defined to be %d\n",ARG_MAX+0);
#else
    printf("no symbol for ARG_MAX\n");
#endif
#ifdef _SC_ARG_MAX
    pr_sysconf("ARG_MAX =",_SC_ARG_MAX);
#else
    printf("no symbol for _SC_ARG_MAX\N");
#endif
#ifdef MAX_CANON
    printf("MAX_CANON defined to be %d\n",MAX_CANON+0);
#else
    printf("no symbol for MAX_CANON\n");
#endif
#ifdef _PC_MAX_CANON
    pr_pathconf("MAX_CANON =",argv[1],_PC_MAX_CANON);
#else
    printf("no symbol for _PC_MAX_CANON\n");
#endif
    exit(0);
}
static void pr_sysconf(char *mesg,int name)
{
    long val;
    fputs(mesg,stdout);
    errno=0;
    if((val=sysconf(name))<0){
    if(errno!=0){
    if(errno==EINVAL)
    fputs("(not supported)\n",stdout);
    else
    err_sys("sysconf error");
    }
    else
    {
    fputs("(no limit)\n",stdout);
    }
    }
    else{    
    printf(" %ld\n",val);
    }
}
static void pr_pathconf(char *mesg,char *path,int name)
{
    long val;
    fputs(mesg,stdout);
    errno=0;
    if((val=pathconf(path,name))<0){
    if(errno!=0){
    if(errno==EINVAL)
    fputs("(not supported)\n",stdout);
    else
    err_sys("pathconf error,path=%s",path);
    }else{
    fputs("(no limit)\n",stdout);
    }
    }else{
    printf("%ld\n",val);
    }
}

2.5.5 不確定的執行時限制

前面已提及某些限制值可能是不確定的。我們遇到的問題是:如果這些限制值沒有在標頭檔案中定義,那麼在編譯時也就不能使用它們。但是,如果它們的值是不確定的,那麼在執行時它們可能也是未定義的

處理不確定結果這種情況的正確方法與如何使用所分配的儲存空間有關。例如,如果我們為getcwd呼叫分配空間(返回當前工作目錄的絕對路徑名),如果分配空間太小,則返回一個出錯,並將errno設定為ERANGE。然後可呼叫realloc來增加分配的空間並重試。不斷重複此操作,直到getcwd呼叫成功執行

程式清單2_3 為路徑名動態地分配空間

#include"apue.h"
#include<errno.h>
#include<limits.h>
#ifdef PATH_MAX
static int pathmax=PATH_MAX;
#else
static int pathmax=0;
#endif

#define SUSV3 200112L
static long posix_version=0;
#define PATH_MAX_GUESS 1024

char* path_alloc(int *sizep)
{
    char *ptr;
    int size;
    if(posix_version==0)
    posix_version=sysconf(_SC_VERSION);
    if(pathmax==0){
    errno=0;
    if((pathmax=pathconf("/",_PC_PATH_MAX))<0){
    if(errno ==0)
    pathmax=PATH_MAX_GUESS;
    else
    err_sys("pathconf error for _PC_PATH_MAX");
    }
    else{
    pathmax++;
    }
    }
    if(posix_version < SUSV3)
    size=pathmax;
    if((ptr=malloc(size))==NULL)
    err_sys("malloc error for pathname");
    if(sizep!=NULL)
    *sizep=size;
    return(ptr);
}

2.8 基本系統資料型別

標頭檔案<sys/types.h>中定義了某些與實現有關的資料型別,他們被稱為基本系統資料型別(primitive system data type)。還有很多定義在其他標頭檔案中。

基本資料型別

clock_t 時鐘滴答計數器(程序時間)
comp_t  壓縮的時間滴答
dev_t   裝置號(主和次)
fd_set  檔案描述符集
fpos_t  檔案位置
gid_t   數值組ID
ino_t   i節點編號
mode_t  檔案型別,檔案建立模式
nlink_t 目錄項的連結計數
off_t   檔案長度和偏移量(帶符號的)
pid_t   程序ID和程序組ID(帶符號的)
pthread_t   執行緒ID
ptrdiff_t   兩個指標相減的結果(帶符號的)
rlim_t  資源限制
sig_atomic_t    能原子性地訪問的資料型別
sigset_t    訊號集
size_t  物件(如字串)長度(不帶符號的)
ssize_t 返回位元組計數的函式(帶符號的)
time_t  日曆時間的秒計數器、
uid_t   數值使用者ID
wchar_t 能表示所有不同的字元碼