希望sco unix圖書program2 6多字節(jié)字符和寬_第1頁
希望sco unix圖書program2 6多字節(jié)字符和寬_第2頁
希望sco unix圖書program2 6多字節(jié)字符和寬_第3頁
希望sco unix圖書program2 6多字節(jié)字符和寬_第4頁
希望sco unix圖書program2 6多字節(jié)字符和寬_第5頁
已閱讀5頁,還剩211頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

提升無符號和值的保 使用const和 普通對象文件格式 SCOCIEEE標(biāo)準(zhǔn)的單精度雙精度和擴展精度的數(shù)據(jù)類型運算和轉(zhuǎn)換為了IEEE還提供了庫函數(shù)注若需要的關(guān)于C編譯系統(tǒng)如何支持IEEE標(biāo)準(zhǔn)的信息參見IEEE要注 386™的微處理器的浮點子系統(tǒng)基于二進制浮點運算標(biāo)準(zhǔn)即標(biāo)準(zhǔn)7541985若要有關(guān)此標(biāo)準(zhǔn)的內(nèi)容寫信至IEEEServiceCenter,445HoesLane,Piscataway,NJ,08854,或者打 20198100600域符號位正數(shù) 指數(shù)以1270域符號位正 0 對于擴展精度第63位總是為 并且小數(shù)點緊跟在此位后其他格式的數(shù)在小數(shù)請參見規(guī)范數(shù)域符號位正數(shù)負(fù)數(shù)指數(shù)以16383小數(shù)第631其次是小數(shù)點620比特位為小數(shù) 指數(shù)域包含一個固定底數(shù)的指數(shù)對于單精度而言底數(shù)為127 雙精度為1023 這樣對于單精度而言規(guī)范浮點數(shù)的指數(shù)范圍為 包含兩界對于雙精度而言范圍為1022到1023 在單精度和雙精度格式中存在一個關(guān)聯(lián)的隱含位這個隱含位及其名稱不顯式地邏輯上對于規(guī)范操作數(shù)此隱含位的值是而且緊靠二進制小數(shù)點的左邊即20的位置12223的值對于雙精度而言表示包含1到 252的值對于擴展精度沒有隱含位所以表示1到 263的所以規(guī)范單精度數(shù)的范圍正或負(fù)為2126到 2 2127包含兩規(guī)范雙精度數(shù)的范圍正或 為21022到 2 21023包含兩規(guī)范擴展精度數(shù)的范圍正或負(fù)為216382到 2 216383包含兩 所以非規(guī)范單精度數(shù)的范圍正或負(fù)為2126 222 非規(guī)范雙精度數(shù)的范圍正或負(fù)為2 25121073到 2 21022包兩界 所以其范圍正或 為2163822 216445 2 2 NaN非中 0 1X 正 負(fù) X 1 在域中可存的最小值全0 NotMMNonzero域中至少有一位為1 在同一格式中正無窮大比其他所有可表示的數(shù)都大對正無窮大的算術(shù)運算是相當(dāng)直觀的例如把任何可表示數(shù)和無窮大相加是有效運算其結(jié)果是正無窮大從正無窮大自身做減法是無效的如果某些算術(shù)運算溢出并且溢出中斷被那么在某種舍入方式下的非數(shù)NaNNaNNaNNaNNaNNaN在絕NaNNaN是由算術(shù)運算本身產(chǎn)生的例如當(dāng)無效運算中斷被時0除0就產(chǎn)生一個靜態(tài)NaN浮點算術(shù)提供了四種舍入模式能影響到絕大多數(shù)浮點運算的結(jié)果這些模式定義在頭文件ieeefp.h中 ->FP_RP向正無窮大舍入FP_RM向負(fù)無窮大舍入FP_RZ0舍入截尾fp_rndfpgetround(void**/fp_rndfpsetround(fp_rnd);/*設(shè)置舍入模式*//*注本節(jié)中的例子例如上面的一個例舉了函數(shù)原型關(guān)于函數(shù)原型的信息參見編程工具指南中的函數(shù)定義缺省的舍入模式是舍入到最接近的數(shù)在C里浮點到整數(shù)的轉(zhuǎn)換總是采用截尾而關(guān)于fpgetround和fpsetround的信息查看 00所有對信號NaN的運算產(chǎn)生一無效運算異常00無窮大減無窮大無窮大除無窮大都產(chǎn)生此異常當(dāng)一個靜態(tài)NaN和大于或小于關(guān)系運算符比較時產(chǎn)生一個其他異常例如由于除法造成的溢出則產(chǎn)生下溢異常信號當(dāng)下溢中斷被只有在運算結(jié)果很小并且檢測到精度損失時才產(chǎn)生下溢異常如果一個運算的舍入結(jié)果與無限精確的結(jié)果不同就產(chǎn)生此異常信號非精確異常非常普遍1.0/3.0在In ™的處理器上實現(xiàn)浮點運算包括另外一種異常類型被稱為非規(guī)范異常C的ANSI標(biāo)準(zhǔn)有一個規(guī)定允許表達式在沒有double或longdouble操作數(shù)的情況下用單精度來計算C編譯器支持這種規(guī)定除非顯式地為 浮點常數(shù)都是雙精度的例如在下列語句floata,floats;s*sd用單精度相對于雙精度時運算會導(dǎo)致精度損失如下例所示floatf=8191f*8191.f;/*float來運算*/printf("Asfloat:%f\nAsdouble%f\n",f,d); 同樣longint變量如同int比float變量有更高的精度考慮下inti,j;第一個printf()語句輸出7ffffff而第二個顯示0第二個printf()顯示0是因為最接近0x7ffffff的float值為0x 當(dāng)這個值轉(zhuǎn)化為整數(shù)時結(jié)果就是0并且產(chǎn)生一個浮點非精確結(jié)果異常如果這個異常被允許則產(chǎn)生一個中斷一個被返回float結(jié)果的函數(shù)實際上既可能返回float也可能返回double如果函數(shù)值float的精度有關(guān)于此的所有內(nèi)容都是透明的例如floatretflt(float);/*float*/floatretdbl1();/*實際返回double*/doubletakedbl(x);CIEEEIEEE雙擴展精度運算的實現(xiàn)方法無論是中間結(jié)果還是最終結(jié)果都按照它們各自的隱含精度計算ANSIC包括了一種新數(shù)據(jù)類型稱為longdoubleIEEE擴展精度格式擴doubleIn386™double64longdouble80位所有算術(shù)運算/ANSIClongdoubledouble更寬在In™longdouble的完全的支持CIEEEC編譯系統(tǒng)未能完全符合ANSI/IEEE標(biāo)準(zhǔn)7541985要求或其的問題的討論IEEE要求當(dāng)前的舍入模式對浮點到整數(shù)格式的轉(zhuǎn)換起作用但是C語言要求用截尾如同向0舍入來進行這些轉(zhuǎn)換在C編譯系統(tǒng)中浮點到整數(shù)的轉(zhuǎn)換是用截尾實現(xiàn)的對于溢出條件浮點數(shù)到整數(shù)的轉(zhuǎn)換應(yīng)該產(chǎn)生整數(shù)溢出或無效運算的信號在當(dāng)前的實現(xiàn)中整數(shù)溢出標(biāo)志被置位了但是沒有辦法啟動溢出中斷啟動整數(shù)溢出中斷會導(dǎo)致由于流水線暫停而產(chǎn)生的不可忽視的性能IEEE0UNIX操作系統(tǒng)相應(yīng)地要求此平方根運算返回0.0并把errno置為EDOMcc命令使用-aods30C00.0并且errnoEDOM0IEEE標(biāo)準(zhǔn)產(chǎn)生無效運算并返回浮點數(shù)除了通常的關(guān)系小于等于大于還有第四種關(guān)系無序當(dāng)至少有一個NaN時就產(chǎn)生無序的情況NaN和所有的值包括自己都比較成無序關(guān)系==!=>如果沒有用于對無序測試的判定你可以使用isnand()或者isnanf()來檢測參數(shù)是否為 關(guān)于isnand()和isnanf()的信息參見isnan(S)對于無序操作數(shù)>>=<=關(guān)系會產(chǎn)生無效運算編譯生成的代碼對比較的無序結(jié)果無防護作用如果中斷被了對無序情況的處理會和如果條件為真時的一樣這樣也許對于==和!=判定無序情況不會導(dǎo)致無效運算對無序情況的處理會和當(dāng)操作數(shù)不等時的一樣且結(jié)果正確在IEEE浮點算術(shù)中(a>b)和(!(a<b))是不一樣的當(dāng)ba的比較結(jié)果為無序時這種差異就表現(xiàn)出來而C編譯器對這兩種情況生成相同的代碼和無窮大理想狀況下無論printf()輸出什么結(jié)果scanf()通過相同的格式總能讀入但是對于浮點格式scanf()不能識別NaN和無窮大然而由于這些特殊情況總是用于對錯誤浮點運算的診斷所以輸出這些結(jié)果相對于讀入更重要依照標(biāo)準(zhǔn)C注本章的信息來源于一系列文章它們各自討論了關(guān)于某一特定過程的這些文章原先是由DavidProsserDistinguishedMemberofTechnicalStaff,USL為USL內(nèi)部時提升無符號和值的保留ANSIC對語言最徹底的改變是從C語言引入了函數(shù)原型通過給每個函數(shù)指定lint轉(zhuǎn)換為函數(shù)所需要的類型ANSIC包括了用于控制新舊風(fēng)格函數(shù)混合的規(guī)則因為有無數(shù)條現(xiàn)有的C代碼能夠且應(yīng)該被轉(zhuǎn)化為可使用原型當(dāng)你完全編寫一個新程序時應(yīng)該在頭文件里使用新風(fēng)格的函數(shù)而在C源文件里使用新風(fēng)格的函數(shù)和定義不過如果有人要把代碼放到前ANSIC編譯器里那么就要在頭文件和源文件里使用宏_STDC_只在ANSIC編譯系統(tǒng)中定義如果所有函數(shù)都用原型和定義了并且正確的源文件包含了相應(yīng)的頭文件那么只要對同一對象或函數(shù)的兩個互不兼容的出現(xiàn)在同一作用域里符合ANSIC的編譯器就會發(fā)出一個診斷信息因而所有的調(diào)用都必須符合函數(shù)定義從而消除了最通常的C編程錯誤-v選項時給出參數(shù)類型和數(shù)目不匹配的警在頭文件中加入函數(shù)原型并使源文件以它的局部靜態(tài)函數(shù)的原型起始包括了所有的函數(shù)調(diào)用但是需要在源文件中輸入兩次局部函數(shù)的接口為了使函數(shù)原型能夠和舊風(fēng)格的函數(shù)定義一起工作兩者都必須指定功能上相同的接口或者依照ANSIC的術(shù)語有兼容類型ANSICvarargs()函數(shù)定義混合了但是對于固定數(shù)量參數(shù)的函數(shù)你可以簡單地指定和在以前的實現(xiàn)中傳遞的參數(shù)類型ANSIC編譯器中根據(jù)缺省的參數(shù)提升直到傳遞給調(diào)用的函數(shù)前每個參數(shù)才被轉(zhuǎn)換這就規(guī)定了所有比int短的整數(shù)都被提升為int大小而float參數(shù)就提升為double這就同時簡化了編譯器和庫函數(shù)原型更易表示傳遞給函數(shù)的就是指定的參數(shù)類型這樣如果對一個已有的舊風(fēng)格的函數(shù)定義寫一個函數(shù)原型就應(yīng)該在函數(shù)原型 signed unsigned signed unsigned不過仍然有兩個與編寫原型有關(guān)的復(fù)雜問題typedef名稱和對短無符號類型的提升如果在舊風(fēng)格函數(shù)中的參數(shù)是用typedef名稱來例如off_t和ino_t那么重要的就是要知道typedef名稱是否命名了一個接受缺省參數(shù)提升作用的類型對于這兩個off_tlong類型所以可以在函數(shù)原型中使用而ino_tunsigned類型所以如果在原型中使用它編譯器會發(fā)生一個診斷信息也許是致命錯誤因為舊風(fēng)格定義和原型指unsignedshortANSICANSICunsignedcharunsignedshortint大小的值的提升規(guī)則參見提升unsigned和數(shù)值的保留 參數(shù)的匹配和你編譯時使用的編譯模式有關(guān)對于-Xt 應(yīng)該使用unsignedint-Xa和-Xc應(yīng)該使用int 最好的辦法盡管違背了第二和第三條選擇的精神是把舊風(fēng)格定義改變?yōu)橹付╥nt或unsignedint類型并使用和函數(shù)原型匹配的類型如果必要的話在輸入函數(shù)后你總可以把它的值賦給使用短類型的局部變量以下是一更新的源文件如上面的第三種選擇局部函數(shù)仍然使用舊風(fēng)格定義而在以前的實現(xiàn)中你不能指定函數(shù)需要的參數(shù)類型但ANSIC允許你使用原型來實現(xiàn)為了支持類于printf()這樣的函數(shù)原型語法包括了特殊的省略號…終結(jié)符因為一個實現(xiàn)中可能需要做特殊的事而要處理可變數(shù)量的參數(shù)ANSIC要求所有這種函數(shù)的因為沒有給參數(shù)中… 部分的名稱在stdarg.h中包含了一個特殊的宏集來提供函數(shù)使用這些參數(shù)的途徑這種函數(shù)的早期版本必須使用包含在varargs.h中的類似的宏本例編寫了一個名為errmsg()的錯誤處理函數(shù)它返回void并且它的固定參數(shù)是一int用來指定錯誤信息的細(xì)節(jié)在這個參數(shù)后面緊跟的也許是一個文件名或者一行數(shù)值或者兩者都有而且此后還有printf()類的格式和參數(shù)用來指定錯誤信息的內(nèi)容為了允許本例能在較早的編譯器中編譯它擴展了僅僅定義在ANSIC編譯系統(tǒng)中的宏_STDC_的用法這樣函數(shù)在相應(yīng)的頭文件中就是errmsg() va_alistva_dclvarargs.h由于舊風(fēng)格可變參數(shù)機制不允許任何固定參數(shù)的規(guī)則至少是非正式的我們需要在可變部分前重新排列它們以便…va_start()宏還有一個參數(shù)在…符號前的參數(shù)的名稱注ANSIC作為一個擴展允許函數(shù)在沒有固定參數(shù)時和定義int對于這種函數(shù)va_start()調(diào)用時需要另一個空參數(shù)va_arg()va_end()ANSIC版本下運行因為va_arg()的值對vfprintf()宏 errmsg(FILENAME,"<commandline>","cannotopen:%s\n",提升以下信息出現(xiàn)在用于C標(biāo)準(zhǔn)草稿的基礎(chǔ)原理中需要無符號保留算術(shù)轉(zhuǎn)換的程序往往表現(xiàn)迥異但也許沒有太大問題這是對當(dāng)?shù)谝焕诙谌贑編程語言Kernighan和Ritchie第一版中無符號特指一種類型沒有unsigned unsignedshorts或者unsignedlongs但以后的大多數(shù)C編譯器把這些類型加了進去一些編譯器沒有unsignedlong但包括了另外兩個 通常當(dāng)這些新類型和別的類型在ANSIC編譯器和其他大多數(shù)C編譯器使用一簡單規(guī)則 無符號保留當(dāng)一個無符號類型需要擴展時它被擴展為一個無符號類型當(dāng)一個無符號類型和有符號類型混合時另一個由ANSIC指定的規(guī)則被稱為值保留其結(jié)果的類型和操作數(shù)類型的相對長度unsignedcharunsignedshort被擴展時如果一個int的長度足夠表示所有較小的類型的值那么結(jié)果就是int類型否則結(jié)果是一個unsignedint值保留規(guī)則對只有在轉(zhuǎn)換-Xt和K&R-Xk模式下ANSIC編譯器才使用無符號保留提升在另外三種模式下使用值保留提升規(guī)則編譯器會對每個表達式給出警告如果它們的運行和警告輸出級別等于或高于-W2的編譯器所使用的提升規(guī)則有關(guān)而且總是可以通過把目的行為顯式化來消除這些警告如下面實例所示第一例在以下代碼假定unsignedcharintint{inti=-unsignedcharuc=1;return(i+us)<17;}注ANSIC編譯器中l(wèi)ine6:warning:semanticsof"<"changeinANSIC;useexplicitcast加法結(jié)果的類型是int 值保留或者unsignedint無符號保留 種類型中不會有變化二的補碼機制是i:111…110(-+uc:000…001(-111…111(-1orint這個位代表1unsignedintUINT_MAX因此如果結(jié)果類型是int則使用一個有符號的比較Less_tuantest為真如果結(jié)果類型是unisignedint則使用一個無符號的比較Less_thantest為假valuepreserving:unsignedpreserving:(i+(unsignedint)uc)<17因為這個表達式是模糊的因為不同的編譯器會生成不同含義的代碼一個摒棄的同樣的情況也要應(yīng)用于位域值的提升在ANSIC中如果一個int或unsignedint位域中位的個數(shù)少于一個int中的位的個數(shù)提升后的類型是int否則提升后的類型是unsigned 在大多數(shù)舊的C編譯器中對于顯式的無符號位域提升后的類型是unsignedint否則是int在用無格式位域表示無符號值的計算機上全長的位域如8char16位32intlong和enum會被轉(zhuǎn)變?yōu)橄鄳?yīng)的無符號類型以便代碼生成任何機器上的任何全長的位第二例在以下代碼中假定unsignedshortunsignedcharintint{unsignedshortus;unsignedcharuc;returnuc<us;}intunsignedint所以比較結(jié)果有時是無符號的有時是有符號的但是ANSIC編譯器不會警告你因為這兩種選擇的結(jié)果是一樣的對于特定的整數(shù)常量類型的規(guī)則隨著表達式的改變而改變了以前一個無后綴的十進制常量僅當(dāng)值適合int時類型才為int而無后綴的八進制或十六進制常量值僅當(dāng)值適合unsignedintint其他情況一個整數(shù)常量類型為long當(dāng)值不適合結(jié)果的類型時在ANSIC中常量類型是以下對應(yīng)于數(shù)值的列表中首先碰到的類型int,long,unsignedunsuffixedoctalorint,unsignedint,long,unsignedULlong,unsignedULANSIC整數(shù)常量類型規(guī)則只是用于轉(zhuǎn)換模式ANSIC和相符的模式使用新的規(guī)則第三例以下代碼假定int16int{intreturn}因為十六進制整數(shù)類型是int2的補碼的值為1或者unsignedint2的補碼的值為65535在非ANSIC編譯器上-Xt和-Xk模式比較結(jié)果為真而在ANSIC編譯器上-Xa-Xc和-Xm模式結(jié)果為假ANSIC編譯器對此有異議非ANSIC表現(xiàn)為ANSICi>(unsigned后綴字符UANSICC最不特殊的部分就是關(guān)系到把源文件從一串字符轉(zhuǎn)變?yōu)橐幌盗杏糜诜治龅臉?biāo)記的操作這些操作包括識別空白部分包括注釋把連續(xù)字符轉(zhuǎn)變?yōu)闃?biāo)記處理命令行的預(yù)處理和替換宏但是它們各自的順序從沒有保證過舊的CANSIC替換源文件中的每個三字符序列ANSIC總共有九個三字符序列它們僅被創(chuàng)造出來當(dāng)作缺陷字符組的特例只要C需要并且它們的名稱是不包括在ISO646#^|\]{}ANSIC編譯器必須能夠理解這些序列但是除了有模糊代碼有這種可能的化它ANSICK&R模式-Xt或-Xk甚至是注釋中替換了一個三字符它就會給出警告例如考慮以下情況/&lowest;comment/&lowest;stillcomment? /&lowest;comment&lowest;/&lowest;stillcomment?第二行的第一個 成為注釋的結(jié)尾下一個標(biāo)記是#include源文件每個換碼序列在字符常量和字符串字符里都被解釋每個預(yù)處理標(biāo)記被轉(zhuǎn)換為一個常規(guī)標(biāo)記編譯器正確地分析它們并且產(chǎn)生代所有外部對象和函數(shù)的都分解清楚并且產(chǎn)生最后的程舊的前ANCIC編譯器例如以前版本的rcc既這種簡單的步驟序列也不在應(yīng)用這些步驟時提供保證一個獨立的預(yù)處理器實際上在替換宏和處理指令行的同時來識別標(biāo)記其輸出完全被編譯器重新標(biāo)記化了然后才分析語句和產(chǎn)生代碼因為在預(yù)處理器中標(biāo)記化過程是一點一點進行的而宏的替換是基于字符操作來完成的不是基于標(biāo)記的所以在預(yù)處理過程中標(biāo)記和空白的處理會有很多變化從這兩種方法來看存在一些不同之處本節(jié)的其余部分會討論由于行的接合宏的替換字符串化和標(biāo)記粘貼發(fā)生在宏替換時代碼的行為會如何的改變ANSIC編譯器中反斜杠/新行對只在作為繼續(xù)一個指令一個字符串文字或者把字符常量寫到下行時才被允許ANSIC/新行對就能把任何事寫到下一行結(jié)果就是一個邏輯源行所以任何依賴于對在反斜杠/新行對兩邊的ANSIC之前宏的替換處理從沒有被重點地詳細(xì)描述過這種含糊導(dǎo)致了許多不同的實現(xiàn)并且任何比明確的常量替換和簡單的?:類詳細(xì)宏更流行的事物的有關(guān)代碼都有可能不可移植本書不討論的C和ANSIC版本在宏的替換實現(xiàn)上的所有微妙很微妙的差別幸運的是除了標(biāo)記粘貼和字符串化幾乎所有的宏替換的使用都產(chǎn)生和以前相同系列的標(biāo)記而且ANSIC宏替換算法可以做到舊的C版本理不能做的事例如#definenamenamenameC預(yù)處理器會產(chǎn)生大量括號和星號最終會抱怨這種宏的遞歸ANSIC對宏的替換方法的主要改變是要求宏的參數(shù)除了宏替換操作符#和##的操作數(shù)的遞歸擴展優(yōu)先于它們在替換標(biāo)記列表中的替換但是這種改變在結(jié)果標(biāo)記中很少注ANSIC中下面用a++標(biāo)記的例子產(chǎn)生一個關(guān)于使用舊特征的警告只有在轉(zhuǎn)換和K&R模式-Xt和-Xk中的結(jié)果才會和以前版本的C一樣ANSIC編譯器中下列語句產(chǎn)生字符串文字xy!#definestr(a)"a!" str(xy)因此預(yù)處理器在內(nèi)部字符串文字和字符常量中查找象宏參數(shù)的字符ANSIC認(rèn)識到這種特征的重要性但是不能允許在標(biāo)記部分的操作在ANSIC中所有對上述宏的調(diào)用產(chǎn)生字符串文字a!ANSIC中獲得舊的效果我們使用#宏替換操作符#definestr(a)#a"!"str(xy)以上生成兩個字符串文字x 和 在連接后就生成x不幸的是沒有對字符常量相似操作的直換這個特征的主要用法如#defineCNTL(ch)(037&'ch') (037&其值為ASCII字符control-L最佳的解決辦法是改變所有這個宏的用法至少可以自動完成此事為#defineCNTL(ch)(037&ANSICx#defineself(a)#defineglue(a,b)a/&lowest;&lowest;/b self(x)1glue(x,ANSIC不能同意它們認(rèn)為有重要能力的任何法在ANSIC中以上兩個調(diào)用會產(chǎn)生兩個獨立的標(biāo)記x1上述兩個方法的第二個可以通過使用##宏替換操作符來針對ANSIC重寫#defineglue(a,b)a##bglue(x,1)由于##入了調(diào)用中它比其他形式更少用到注僅當(dāng)_STDC_被定義時#和##const和const是CANSICvolatile被ANSIC創(chuàng)造后在實際效果上類型限定符的概念就產(chǎn)生了這仍然是ANSIC的const和volatile是一個標(biāo)志類型的部分而不是它的類但是它們的特殊之處在于它們經(jīng)常從類型的的最頂層部分處刪去這發(fā)生在一個對象從表達式計算中獲得值時恰好就在一個lvalue成為一個rvalue時這些術(shù)語來源于原型的賦值LR其中左邊必須直接指向一個對象一個lvalue而右邊只要是一個值一個rvalue所以只有l(wèi)value的表達式能夠被constvolatile或兩者限定由于類型限定符會修改類型名稱和派生類型它們是特殊的派生類型是C中能夠被重復(fù)使用而產(chǎn)生復(fù)雜類型的部分指針數(shù)組函數(shù)結(jié)構(gòu)和聯(lián)合除了函數(shù)constint用類型constint和初始化一個對象其值不會被一個正確的程序改變對C而言關(guān)鍵字的次序不重要例如intconst和constxonstint用指向constint的指針類型了一個對象其值開始指向前一的對象注意 它指向一個限定類型因而指針在程序執(zhí)行中實際上可以指向任何int但是pci不能用來修改它指向的對象除非使用一個摒棄如下所示&lowest;(int&lowest;)externint&lowest;const表示在程序的某處有一個全局對象的定義類型為指向int的const指針在這種情況下cpi中const在&lowast后面以下一對產(chǎn)生相同效typedefint∗INT_PTR;externconstINT_PTRcpi;這些可以按以下組合起來其中一個對象為指向constint的const類constint∗const從事后來看readonly是對關(guān)鍵字而言比const更好的一個選擇如果以這種方式讀取const如char∗strcpy(char∗,constchar很容易理解為第二個參數(shù)只被用來字符值而第一個參數(shù)會無疑地重寫它指向的字符而且除了在上例中cpi的類型是指向一個constint的指針你還可以改變它用其他方式指向的對象的值除非它實際指向為constint類型的對象const兩個主要的用法是把長編譯時間初始化信息表為不可變及指定指針第一用法使一程序據(jù)部分夠此序中其他同的調(diào)用共享就象程序代碼能做到的那樣而且使得對修改原來不可變數(shù)據(jù)的企圖立刻被內(nèi)存保護缺陷之類第二中用法就象在幫助定位潛在的錯誤先于在演示中產(chǎn)生內(nèi)存缺陷例如如前面的例子都使用了const因為它在概念上更簡單但是當(dāng)必須使用準(zhǔn)確的語義時就得使用volatile對于程序員來說volatile有多種含義對于編譯器編寫者它表示當(dāng)這樣的對象時不采用代碼生成的快捷方式此外在ANSIC中程序員的職責(zé)就是聲明每個有volatile限定類型的相應(yīng)特定屬性的每個對象一個在函數(shù)中的自動時期的對象它調(diào)用setjmp而值在setjmp調(diào)用和相應(yīng)的longjmp調(diào)用中改變這樣這個看起來的無限循環(huán)while(flat);只要flag是volatile限定類型就是可以理解的假定某些異步會在將來把flag設(shè)置為0 否則編譯同樣可以隨意改變上述循環(huán)因為falg值在循環(huán)體內(nèi)是不可變的到一個真的完全忽略flag值的無限循環(huán)中第四個涉及到調(diào)用setjmp的函數(shù)的局部變量的例子更有關(guān)系如果仔細(xì)閱讀了有關(guān)setjmp和longjmp行為的內(nèi)容你會發(fā)現(xiàn)沒有對符合第四種情況的對象值的保證對于longjmpsetjmplongjmp的函數(shù)件時為了已保存的寄存器值檢查每個堆??蚣芤员愕玫阶詈玫慕Y(jié)果異步產(chǎn)生堆??蚣艿目赡苁沟眠@種代價昂貴的工作更為所以大多數(shù)實現(xiàn)只是記錄下不希望的副作用和使用不昂貴的方法當(dāng)一個自動對象為volatile限定類型時編譯系統(tǒng)知道必須生成和程序員編寫的一樣的代碼所以這種自動對象的大多數(shù)最近的值總是在內(nèi)存里不只在寄存器里并且這樣就能保證在longjmp被調(diào)用時得到更新首先ANSIC的只影響庫函數(shù)但是的最終階段 亞洲化亞洲化在亞洲環(huán)境中的基本是需要I/O的大量表意文字為了可以在通常的計算機體系的限制下工作這些表意文字被編碼成一串字節(jié)輔助操作系統(tǒng)應(yīng)用程序和終端把這些字節(jié)序列理解為獨立的表意文字此外所有這些編碼允許常規(guī)單字節(jié)字符和表意文字字節(jié)序列混合在一起識別獨特的表意文字的復(fù)雜度和使用的編碼方案有關(guān)多字節(jié)字符是由ANSIC定義的用來標(biāo)志表意文字編碼后的字節(jié)序列而不論采用了什么編碼方案所有多字節(jié)字符是被稱為擴展字符集的成員一個常規(guī)的單字節(jié)字符是一個多字節(jié)字符的特例實際上對編碼的唯一要求就是沒有多字節(jié)字符可以把ANSIC每個多字節(jié)字符都是自我識別的從而任何多字節(jié)字符能夠簡單地插在多字節(jié)字符對之間ANSIC設(shè)置的高階位特定的換檔字節(jié)的出現(xiàn)改變了相應(yīng)字節(jié)的解釋例如大多數(shù)流行字符終端用來進入和推出行模式的方法對于使用與換檔態(tài)有關(guān)的用多字節(jié)字符編寫的程序ANSIC有額外的要求即每個注釋字符串文字字符常量和頭文件名稱都必須始終在非換如果所有字符都有統(tǒng)一的字節(jié)或位數(shù)那么就能消除處理多字節(jié)字符的某些不便之處1632位大小的整數(shù)值來注65000ANSICtypedefwchar-t用來作為實現(xiàn)中定義的整數(shù)類型以保證大到對于每個寬字符都有一個對應(yīng)的多字節(jié)字符反之亦然對應(yīng)于常規(guī)的單字節(jié)字符的寬EOF的值也可以存在一wchar_t中就象EOF也許不能表示為一個char一樣 注在中參見函數(shù)簡化寬字符串的處理但是對大多數(shù)應(yīng)用程序而言沒有必要把每個多字節(jié)字符轉(zhuǎn)變?yōu)榛蜣D(zhuǎn)自于寬字符象diff這樣的程序?qū)⒆x入和寫出多字節(jié)字符而只需檢查確切的字符對字符的匹配復(fù)雜的使用常規(guī)表達式格式匹配的程序如grep只需能夠理解多字節(jié)符但是只有管理常規(guī)表達式的普通函數(shù)集需要這種知識grep程序自身不需要其他的特殊為了使程序員在亞洲環(huán)境中工作更靈活A(yù)NSIC提供了寬字符常量和寬字符串文字它們除了以字母L開頭外和其他非寬版本的字符有相同的格式 "abcyz" L"abcyz"寬字符串文字注意到多字節(jié)字符在常規(guī)和寬字符中都是有效的用于產(chǎn)生表意文字的字節(jié)序列是用特殊編碼的但是如果它由多于一個字節(jié)組成的話字符常量’是由執(zhí)行定義的正如’ab’是由執(zhí)行定義的一個常規(guī)字符串文字包含有引號指定的包括多字節(jié)字符在內(nèi)的字節(jié)除當(dāng)編譯系統(tǒng)遇到寬字節(jié)常量或?qū)捵址淖謺r每個多字節(jié)字符被轉(zhuǎn)換為一個寬字符就象調(diào)用mbtowc()函數(shù) 這樣L’類型就是wchar_tL”abc yz”類型就是長度為8的wchar_t數(shù)組正如常規(guī)字符串文字那樣每個寬字符串文字有一個附加的零值元素始化wchar_t數(shù)組wchar_t∗wp=L"a";wchar_tx[]=L"a wchar_ty[]={L'a',L',L'z',wchar_tz[]={'a',L','z',在上述例子中x,yz這三個數(shù)組以及由wp指向的數(shù)組都有相同的長度并且都在標(biāo)準(zhǔn)化過程的早期ANSI標(biāo)準(zhǔn)就選擇把庫函數(shù)宏和頭文件包括為ANSIC的一部分這些宏頭文件和函數(shù)對于編正可移植C程序而言是很必要的但是它們也產(chǎn)生了大量的保留名稱集本節(jié)提供不同范疇的保留名稱和部分它們的保留原理最后是一個規(guī)則集以便你可以遵守這些規(guī)則而使你的程序避開這些保留名稱為了適合已有的應(yīng)用ANSIC選擇了類于printf和NULL的名稱否則會使已有的C程序不相符合而且顯然會使他們對已有應(yīng)用標(biāo)準(zhǔn)化的規(guī)章遭到但是每個這樣的名稱都會減少C程序中可自由使用的名稱集從另一方面來說在標(biāo)準(zhǔn)化前開發(fā)者可以自由地把新的關(guān)鍵字加入到編譯器中以及把新的名稱加入頭文件中這就意味著沒有程序可以保證能從一個版本到另一版本都可編譯成功并且能從一個銷售商獨立地移植到另一個那兒這樣作了一個的決定限制所有相符的應(yīng)用使用任何除了有特殊形式的額外的名稱正是由于這個決定而不是其他的使得大多數(shù)C編譯系統(tǒng)基本一致然而32250個名稱其中沒有一個有任何特殊assertlocalestddefctypematherrnosetjmpstdlibfloatsignallimitsstdargtime大多數(shù)應(yīng)用會提供的頭文件但是一個嚴(yán)格相符的ANSIC程序只會使用這些其他標(biāo)準(zhǔn)在這些頭文件中的內(nèi)容上略有不同例如POSIXIEEE1003.1指定在stdio.h中為了使這兩個標(biāo)準(zhǔn)共存POSIX要求宏_POSIX_SOURCE在包含任何頭文件前被#define以保證這些附加的名稱存在實際上POSIX認(rèn)為情況總是相反即_POSIX_SOURCE被用來限定頭文件只使用POSIX描述的名稱而缺省是頭文件會包含比POSIX指定的的名稱X/Open的宏是_XOPEN_SOURCE以下章節(jié)會ANSIC要求保證頭文件是自足和冪等的頭文件不需要在開始或結(jié)尾處#include其他的頭文件而且每個保證頭文件可以被多次#include而不會產(chǎn)生任何問題標(biāo)準(zhǔn)還要求頭文件被#include在安全的環(huán)境中以便保證頭文件中的名稱不改變對于庫標(biāo)準(zhǔn)提出了在實現(xiàn)上的進一步的限定過去大多數(shù)程序員知道通常在遇到有趣的程序行為后不要在UNIX系統(tǒng)的程序里使用象read和write這樣的名稱而ANSIC要求只有被標(biāo)準(zhǔn)保留的名稱可以在實現(xiàn)中被_POSIX_SOURCE或者_XOPEN_SOURCE的程序都有未定義的行但是未定義行為會有不同結(jié)果如果在一個與POSIX相符的實現(xiàn)中你使用了_POSIX_SOURCE你知道你的程序的未定義行為有某些在特定頭文件中的附加名稱組成而你的程序仍然相符于公認(rèn)的標(biāo)準(zhǔn)這些在ANSIC中的有意存在的使得應(yīng)用可以POSIX標(biāo)準(zhǔn)的實現(xiàn)在遇到類于_POSIX_SOURCE的名這個標(biāo)準(zhǔn)還保留了在頭文件中以下劃線開始的所有其他名稱它們當(dāng)中不包括局部域的常規(guī)文件域標(biāo)志和結(jié)構(gòu)和聯(lián)合標(biāo)志來使用這意味著通常使用名為_filbuf和_doprnt的除了顯式保留的所有名稱標(biāo)準(zhǔn)還保留了為了實現(xiàn)和未來的標(biāo)準(zhǔn)符合特定模式errno ctypeh localehLC_[A-Z].∗mathh currentfunctionnames[fl]signalh(SIG|SIG_)[A-Z].∗stdlibhstr[a-z].∗stringh(str|mem|wcs)[a-在以上列表中以大寫字母開頭的名稱是宏單的規(guī)則你可以遵守從而避免和任何ANSIC的保留名稱發(fā)生在你的源文件的開頭#include所有系統(tǒng)頭文件除了有可能在#POSIX_SOURCE或者_XOPEN_SOURCE后的情況小心在stdarg.h或varargs.h中的va_前綴被 那么幾乎所有以 面的一節(jié)中介紹了標(biāo)準(zhǔn)庫的參見多字節(jié)字符和寬字符 到影響的庫函數(shù)并且給出一些關(guān)于應(yīng)該如何編寫程序來利用這些特征的提示在任何時候C程序有一個當(dāng)前地區(qū)一個描述對應(yīng)于某些民族文化和語言的約定的信息集合地區(qū)的名字為字符串而僅有的兩個標(biāo)準(zhǔn)地區(qū)名稱為C和在源級別的API中除了ods30環(huán)境-aods30每個程序都以C地區(qū)開始這使得所有庫函數(shù)都以它們以前的方式運行地區(qū)是對相應(yīng)于程序調(diào)用的恰當(dāng)約定的應(yīng)用的最佳猜測當(dāng)然C和能夠產(chǎn)生相同的行為其他地區(qū)應(yīng)用提供從應(yīng)用和權(quán)宜的角度來說地區(qū)被劃分為一個范疇集一個程序可以完全改變地區(qū)全部范疇或者一個或多個范疇而不會改變其他范疇通常每個范疇作用于一些不受其他范疇作用的函數(shù)所以臨時而短暫地改變一個范疇是可行的#include/∗…∗/在程序執(zhí)行過程的早期這使得程序的當(dāng)前地區(qū)變到相應(yīng)的地區(qū)版本如果可能的話LC_ALL是替代一個范疇而指定整體區(qū)域的宏以下是標(biāo)準(zhǔn)的范疇 setlocale()函數(shù)返回給定范疇或者LC_ALL的當(dāng)前地區(qū)名稱而當(dāng)?shù)诙€參數(shù)為空指針時就可作為只用于查詢的服務(wù)這樣以下代碼能夠用于改變地區(qū)或有限時期中關(guān)于#include/∗…∗/char∗oloc;/∗…∗/oloc=setlocale(LC_cat,NULL);{/∗usetemporarilychangedlocale∗/(voide)setlocale(LC_cat,oloc);}只要可能并且合適就該擴展已有的庫函數(shù)使之包含和地區(qū)有關(guān)的行為這些函數(shù)分為兩組由ctype.h頭文件字符分類和轉(zhuǎn)換的和那些用于轉(zhuǎn)化為或轉(zhuǎn)變自數(shù)值內(nèi)部可顯示形式的函數(shù)例如printf()和strtod()當(dāng)當(dāng)前地區(qū)的LC_CTYPE范疇不是C時所有的由ctype.h指定的除了isdigit()和isxdigit()的函數(shù)對附加字符都可以返回非零值真在希臘地區(qū)isalpha(')應(yīng)該為真同樣的字符轉(zhuǎn)換函數(shù)tolower()toupper()應(yīng)該正確地處理任何額外的由isalpha()函數(shù)指定的字母字符如實現(xiàn)注釋中ctype.h的函數(shù)幾乎都是由字符參數(shù)作為索引的查表法實現(xiàn)的宏它們的行為在用新地區(qū)值重置表時改變所以沒有性能的影響LC_NUMERIC范疇不是C時也許會變?yōu)槭褂眯?shù)點而不是句點沒有任何對轉(zhuǎn)換數(shù)值為成千上萬獨立類型顯示的形式的規(guī)定但是從可顯示形式轉(zhuǎn)換為內(nèi)部形式時允許使用出了C地區(qū)的附加形式的實現(xiàn)方法那些使用小數(shù)點字符的函數(shù)構(gòu)成printf()scanf()atof()strtod()系列函數(shù)那atof()atoi()atol()strtod()strtol()strtoul()scanf()系列函數(shù)ANSIC當(dāng)前沒有定義這樣的擴展某些與地區(qū)相關(guān)的功能作為新的標(biāo)準(zhǔn)函數(shù)被添加進來除了允許控制地區(qū)自身的setlocale()標(biāo)準(zhǔn)還包括了以下新的函數(shù)和前面討論過的多字節(jié)函數(shù)mblen()mbtowc()mbstowcs()wctomb()wcstombs() 關(guān)的函數(shù)對于數(shù)值這個結(jié)構(gòu)描述了小數(shù)點字符成千上萬的分隔符和分隔符所處的位置結(jié)構(gòu)里還有另外十五個成員用以描述怎樣格式化一個貨幣的值除了兩字符的比較是依據(jù)當(dāng)前地區(qū)的LC_COLLATE范疇strcoll()strcmp()函數(shù)是類似的由于這種比較不象strcmp()是必須的strxfrm()函數(shù)可用來把一個字符串轉(zhuǎn)變?yōu)榱硪粋€從而任何兩個轉(zhuǎn)變后的字符串可以傳遞給strcmp()并且得到一個類似于當(dāng)傳遞兩個轉(zhuǎn)換前的字符時strcoll()會返回的次序strftime()structtmsprintf()的格式并且還有一些與當(dāng)前地區(qū)的LC_TIME范疇有關(guān)的日期和時間的表示這個函數(shù)基于函數(shù)ascftime(S)DennisRitchieC的一個選擇中他讓編譯器可以重新排列涉及數(shù)學(xué)可運算和相關(guān)的相鄰操作符即使這些操作符是在括號中這在CProgrammingLanguageKernighanand 第一版的ReferenceManual 中被標(biāo)志出來但C區(qū)分了表達式副作用分組和估值的不同點inti,∗p,f(void),/∗…∗/Kernighan和RitchieCANSICas 表達式的副作用是它對內(nèi)存的改變和對volatile限定對象的在上述表達式中的副作用是對ip的更新以及對任何函數(shù)f()g()的副作用一個表達式的估值包括產(chǎn)生結(jié)果值的每件事為了估計一個表達式所有指定的副作用都必須發(fā)生在之前或之后的序列點的任何地方并且指定運算要在其特定的組內(nèi)執(zhí)行對于上述表達式i和p的更新必須面語句之后而到這個表達式語句的; 止對函數(shù)的調(diào)用可以面語句之后的任何次序中發(fā)生但是在它們返回前值應(yīng)被使用因為加法是數(shù)學(xué)可換和相關(guān)的Kernighan和Ritchie的C重排可以應(yīng)用于以上表達式為了區(qū)別常規(guī)括號和實際的表達式分組用左右彎括號指定分組KernighanRitchieC規(guī)則下以上都是有效的此外即使所有這些表達式寫成其他的形式這些分組依然有效例如i=加法有溢出時這些分組會產(chǎn)生不同的結(jié)果對于在這些結(jié)構(gòu)中的表達式KernighanRitchieC的僅有的可用資源被用來分割表達式而產(chǎn)生一個特定的分組如果分別辨別上述的分組以下就有可能重寫ANSICANSICANSIC語法的先后次序和相互關(guān)系完全描述了所有表達式的分組所有表達式也要象它們被分析的那樣分組考慮中的表達式就以這種方式分類i={{∗++p+f()}+在ANSIC中表達式不需要分割開以放置意料外的溢出由于不完整和不確切的表述ANSIC經(jīng)常被錯誤的認(rèn)為括號優(yōu)先或依據(jù)括號分類ANSIC何分析的表達式正常的先后次序和相互關(guān)系和括號同等重要as ANSIC最終認(rèn)識到如果應(yīng)用到被描述的目標(biāo)結(jié)構(gòu)上重排規(guī)則實際是asif規(guī)則一個實例ANSIC的asif規(guī)則是一個通用的對可以偏離抽象機制描述的實現(xiàn)的只要這種偏離不改變一個有效C程序的結(jié)果這種重排在經(jīng)典的2ANSICC的部分它在開始部分就隱含著本文描述了非完整類型以及它們可在何處和何時使用ANSIC的類型分成三個不同的集合函數(shù)對象和非完整類型函數(shù)類型是顯而易見的對象類型包括了其他的事物除非對象的大小不可知標(biāo)準(zhǔn)使用對象類型這個術(shù)語來指定命名的對象必須有已知的大小但是也有必要知道除了void非完整類型也指向?qū)χ挥腥N不同的非完整類型void 類型void和其他兩個不同在它是一個不能完整化的非完整類型并且被用作一種特殊的在命名同一對象的同一域中用其后的指定了數(shù)組的大小時這個數(shù)組類型就被完整化了同樣當(dāng)一個大小未定的數(shù)組在同一中被和初始化時這個數(shù)組在后到初始化前就是非完整類型的在同一標(biāo)志的同一域中用其后的指定了內(nèi)容后一個非完整結(jié)構(gòu)或聯(lián)合類型就被某些可以使用非完整類型但是其他的需要完整的對象類型那些需要對象類型的是數(shù)組元素結(jié)構(gòu)或聯(lián)合的成員和函數(shù)的局部對象所有其他可以用非完整類型特別是如下所允許的函數(shù)的返回和參數(shù)類型是特定的除了void以這種方式使用的非完整類型必須在函數(shù)定義或調(diào)用前完整化一個void類型的返回指定函數(shù)不返回任何值而且以void為唯一參數(shù)的函數(shù)指定函數(shù)不需要任何參數(shù)注意由于數(shù)組和函數(shù)參數(shù)類型被重寫為指針類型一個看來非完整的數(shù)組參數(shù)類型實際上不是非完整的作為未指定長度的字符指針的數(shù)組main的argv即char∗argv[]的典型就是重寫為指向字符指針的指針大多數(shù)表達式操作符需要完整的對象類型僅有的三個例外是一元&操作符逗號操作符的第一個操作數(shù)和?:操作符的第二和第三個操作數(shù)大多數(shù)接受指針操作數(shù)的操作符同樣接受指向非完整類型的指針除非需要指針運算表中包括了一元的∗操作符即使也許會發(fā)現(xiàn)這很奇怪例如void如果沒有非完整類型C會變得更簡單但是對于void它們是必須的它們也提供了C用別的辦法不能處理而必須結(jié)構(gòu)和聯(lián)合特性處理的辦法如果有兩個結(jié)構(gòu)需要互相指向唯一的辦法不用憑借可能的無效摒棄就是用非完整類型structa{structb∗bp;};structb{structa∗ap;給非完整結(jié)構(gòu)和聯(lián)合類型定義typedef名稱經(jīng)常是相當(dāng)有用的如果有一個包含許多互相指向指針的復(fù)雜數(shù)據(jù)結(jié)構(gòu)簇就需要預(yù)先也許在頭文件的中間有一個對這些結(jié)構(gòu)的typedef列表來簡化typedefstructitem_tagItem;typedefunionnote_tagNote;typedefstructlist_tagList;…structitem_tag{……structlist_tagList∗next;此外對那些內(nèi)容的程序其他部分無用的結(jié)構(gòu)和聯(lián)合頭文件可以一個沒有內(nèi)容的標(biāo)志程序的其他部分可以使用指向這些非完整結(jié)構(gòu)或聯(lián)合的指針而不會有任何問題除非它們試圖使用它的成員externchar…(void)fputs("Alternatetimezone:",stdout);Kernighan和RitchieC中甚至在ANSIC個在ANSIC中術(shù)語兼容類型就是來標(biāo)志那些非常接近的類型的本節(jié)描述了兼容類型和復(fù)合類型聯(lián)合兩個兼容類型的結(jié)果如果C程序值允許每個對象或函數(shù)一次就沒有兼容類型的必要連接允許兩個或多個指向同一實體函數(shù)原型和分別編譯都有這樣的需要毋庸置疑各自的翻譯單元源文件相對于單獨的單元對類型兼容有不同的規(guī)則匹配的標(biāo)量整數(shù)浮點和指針類型必須是兼容的如同它們在同一源文件類型從分別編譯的角度而言包括位域?qū)挾绕ヅ涞慕Y(jié)構(gòu)必須有相同次序的成員聯(lián)合和枚舉成員的次序無所謂當(dāng)不用匹配成員各自的標(biāo)志一個附加的要求是它們的名稱包括未命名成員的名稱缺失必須匹配結(jié)構(gòu)聯(lián)合和枚舉當(dāng)同一域的兩個描述相同的對象或函數(shù)時它們必須指定兼容的類型這兩種類型就組合進一個單獨的和兩者兼容的復(fù)合類型以后會有關(guān)于復(fù)合類型的內(nèi)容兼容類型是遞歸定義的在底層是類型指定關(guān)鍵字這些規(guī)則表示unsignedshort和unsignedshortint一樣而沒有類型指定符的類型和int一樣只要它們是兼容的所有從它們派生出來的其他類型都是兼容的例如如果限定符const和volatile是相同的而且非限定的基本類型是兼容的兩個限定的類型就是兼容的要是兩個指針類型兼容它們指向的類型必須兼容而且這兩個指針必須被相同地限定回想一下對一個指針的限定符是在∗后指定的所以這兩個int∗constcpi;int∗volatilevpi;了兩個指向同一類型int的不同的限定指為了使兩個數(shù)組類型兼容它們的成員類型必須匹配而且如果兩個數(shù)組類型有一特定大小它們必須匹配后一部分意味著非完整數(shù)組類型參見非完整類型同時與另要使兩個有原型的函數(shù)兼容它們必須有相同數(shù)目的參數(shù)包括使用…省略符號而且相應(yīng)的參數(shù)必須兼容要使一個舊風(fēng)格函數(shù)的定義和有原型的函數(shù)類型兼容原型參數(shù)必須不能以省略…要使一個舊風(fēng)格函數(shù)的不是定義和有原型的函數(shù)類型兼容原型參數(shù)必須不要使兩個類型參數(shù)兼容兩者必須在頂層限定符被刪除和函數(shù)或數(shù)組類型轉(zhuǎn)換為在此領(lǐng)域中會有一些奇怪的事例如signedintint一樣其中一個普通的int會標(biāo)志一個無符號行為的數(shù)量類型從效果上說是分立的類型而對大多數(shù)部分ANSIC標(biāo)準(zhǔn)就以這種方式來看待它們從兩個兼容類型構(gòu)造一個復(fù)合類型也是遞歸定義的兼容類型互相區(qū)別的方式都是由于非完整數(shù)組或舊風(fēng)格函數(shù)類型這樣最簡單的復(fù)合類型描述是它的類型和原來的類型都兼容包括每個可用的數(shù)組大小和原來類型的參數(shù)列表為了更好地應(yīng)用軟件消息 在實際代碼里代替了硬代碼消息所有輸入輸 中通過使用消息 言時用戶就不用更換和重新編譯應(yīng)用程序中的硬代碼消息對應(yīng)于特定的環(huán)境變量值程序能夠用指定語言提供所有消息在運行時語言的改變只會引起環(huán)境變量的一個簡單改變毋庸置疑消息 給用戶以極大的靈活性同時為由于更換語言而要修改硬代碼應(yīng)用程序的艱苦任務(wù)提供了另法 由消息源文件用gencat(CP)命令生成它們可以在軟件里通過catopen(S)catgets(S)和catclose(S)例行程序來和使用若要了解關(guān)于通常的消息 或代碼的背景知識參見OpenSoftware 的InternationalizationMadeEasyWhitePage以下所示的代碼給出了如何構(gòu)造一個簡單消息和如何把它加入程序的例子要理解示例中的代碼就應(yīng)理解環(huán)境變量的作用尤其是變量LC_MESSAGESLC_ALLLANGNLSPATH這些變量確切含義在setlocale(S)中定義了在你的程序可以使用消息前它們必須被創(chuàng)建出來以下兩個代碼段是分別用英語例3-1英語消 $set oeveryone.2%a%b%d%T行 每個消息由一組數(shù)字和一個消息數(shù)字標(biāo)識本行定義一組為1的數(shù)21的數(shù)字所以此消息被標(biāo)識為組11其后的消息id是實際的消息體引號是不必要的行 同樣的本行定義了為2的消息數(shù)字標(biāo)識此消息為組1的消息例3-2法語消 $set1Bonjourtoutlemonde.2%a%d%b%Hh%M除了消息體為法語外這些行的作用是和第一例一樣的所以如果使用法語本消息會 3- o,world程 以下代碼使用了在創(chuàng)建消息 中的消息3- o,world程 行 行2 行3 行4~5需要被包括以使用LC_*和LANG環(huán)境變量行6 行9 類型的變量作為 行10 行 串行 行 檢查有匹配 的name參數(shù) 能否被打開如果成功此消就被catalog變量如果程序使用LC_MESSAGE環(huán)境變量就把14~16行17設(shè)置clock變量為UNIX操作系統(tǒng)的時行18-20根據(jù)由變量catalog指定的消息 中的格式格式化時間如果在消息時發(fā)生錯誤那么最終的指定格式就是缺省格式行21-24從變量catalog指定的消息中檢索到組1的消息1如果在消息目錄是出錯最終的字符串是缺省的檢索到的消息顯示出來其后是存在tempbuffer中25catalog 例3-4設(shè)置程序2定義包含消息所在位置的NLSPATH變量%1LANG環(huán)境變量中定義的字符串Ncatopen(S)name參數(shù)提取字符串如果LANG變量中的值是english本例中的消息文件就是./English/o.cat3輸出此定義以使NLSPATH4~5給法語和英語消息創(chuàng)建.cat行6給使用消 和程序都已編譯過了程序就可以執(zhí)行了在繼續(xù)之前必須確認(rèn)英語和法語的o.cat文件分別在./english和./french子 $$LANG=english;export$ 行 行2 設(shè)置環(huán)境變量LANG\* F到english 行3 運行實際的程序本行會產(chǎn)生如下的輸出oeveryone.It’sFriOct1301:03:52$LANG=french;export$ 行1 設(shè)置環(huán)境變量LANG為french 行2 再次運行程序現(xiàn)在的輸出變?yōu)锽onjourtoutlemonde.C’estven13oct01h03注意盡管XG4已經(jīng)建議用特定的格式來定義特定的地區(qū)應(yīng)用中仍可以隨意定義它們自己的格式所以盡管可以設(shè)置LANG為english或french這些定義不符合XPG4的慣例…由于沒有哪個計算機系統(tǒng)是完全可以避免風(fēng)險的所以我們談到計算機時用可信任而不是安全可信任系統(tǒng)通過提供檢測和防止可能的未認(rèn)可的機制獲得對信息的更高級別的控制還有確認(rèn)這些機制運行正常的方法C2級別的信任意味著此系統(tǒng)在它的安全策略可計算性擔(dān)保測試和文檔記錄方面滿足了特定的條件所有UNIX操作系統(tǒng)都提供了一些安全的方法例如讓用戶用口令進行登陸并且提供了對屬主組指定的權(quán)限以及其他對文件和的權(quán)限SCOUNIX系統(tǒng)V/386Release本章中的例子顯示了如何使用可信任設(shè)備來創(chuàng)建受保護的子系統(tǒng)即一個使用可信任實際上所有UNIX操作系統(tǒng)支持標(biāo)準(zhǔn)設(shè)備所以使用標(biāo)準(zhǔn)設(shè)備的程序更有可移植可信任設(shè)備提供了更高級別的安全推薦用于需要防范的應(yīng)用程序以防止對數(shù)據(jù)的對于受保護子系統(tǒng)C代碼有如下特征 在編譯行從CFLAGS使-DsecureWasr#define /*數(shù)據(jù)結(jié)構(gòu)/*#include<sys/audit /*審核數(shù)據(jù)結(jié)構(gòu)#include /*libprotmain()例程中的第一個動作必須是如identity(S)手冊頁里定義的set_auth_parameterssubsys.c例子中的第19set_auth_parameters的程序必須用-lprot標(biāo)志連接例如連接命令ccmyprogram.c當(dāng)你使用可信任設(shè)備時遵循以下原則在運行需要寫敏感系統(tǒng)文件時需要超級用戶權(quán)利或者要操作數(shù)據(jù)結(jié)構(gòu)的程序使用合適的環(huán)境變量和數(shù)據(jù)文件設(shè)置好程序的環(huán)境和信號處理配置以防止用戶使程序作出未知的事情程序應(yīng)該俘獲SIGINTSIGQUIT等等這對使用exec(S)system(S)和popen(S)命令來運行其他程序的程序很有必要SUID程序應(yīng)該始終設(shè)置好IFSPATH和S 從命令解釋程序咨詢程序文件時要使用全稱絕對路徑setuid個子程序時使用setuit(S)setgid(S)來恢復(fù)原來的權(quán)限確認(rèn)當(dāng)調(diào)用子程序前所有被父進程需要的文件都被關(guān)閉了通常在最短的時間里使用這些權(quán)利例如如果你需利區(qū)打開一個文件就使用getenhancedprivopenfiledropenhancedprivwritefile…回想一下access(S)eaccess(S)系統(tǒng)調(diào)用是不同的使用合適的一個在多數(shù)情況下使用eaccess(S)再次檢查有效的UID和GID當(dāng)你運行一個setuid(S)或setgid(S)的二進制時使用access(S) 檢查真實的UID和GID捕獲和處理所有預(yù)料的信號取消任何未完全執(zhí)行的動作是很重要的以防敏感文在所有錯誤情況中使事物保持在可知狀態(tài)中確認(rèn)相關(guān)的異常條件已被恰當(dāng)?shù)靥幚硖幚聿l(fā)如果兩個用戶想同時運行一個程序確信任何要修改的文件在被修處理在文件和用戶輸入格式中的錯誤任何文件都有可能被破壞而導(dǎo)致你程序失敗或使文件或權(quán)限處于不一致狀態(tài)的錯誤都會導(dǎo)致侵入確認(rèn)你的系統(tǒng)安全未受損害檢查你的返回代碼和權(quán)利并且修復(fù)錯誤和不一致在輸入時要特別注意緩沖溢出這會導(dǎo)致不可預(yù)料和潛在的危害行為本章的余下部分給出標(biāo)注的代碼示例來演示如何在安全環(huán)境中編程是在本章中這些代碼示例使用了基本的可信任系統(tǒng)概念TCB可信任計算基準(zhǔn)和DAC自由控制TCB由UNIX和及相關(guān)安全數(shù)據(jù)的可信任實用程序組成TCB實現(xiàn)了系統(tǒng)的安全策略在C2級別這由DAC組成DAC決定一個用戶或關(guān)于可信任系統(tǒng)的基本概念的信息參見NCSCTrustedComputerSystemsEvaluationCriteria(TCSEC)DoDPasswordManagementGuidelinesSCO’sSystemAdministrator’ssubsys.c程序類似于auths(C)但是它顯示用戶的子系統(tǒng)的權(quán)限而不是權(quán)限subsys命令有一個參數(shù)用戶名稱如果沒有指定名稱subsys使用有效用戶ID它顯示帳戶名稱分配此帳戶的人的真實和此帳戶的子系統(tǒng)權(quán)限主要和次要的此程序只能被此帳戶的屬主或帳戶管理員即有auth子系統(tǒng)權(quán)限的用戶運行用任何查詢受保護口令數(shù)據(jù)庫的程序都必須在auth的有效組IDEUID中運行為了安裝這個程序要生成二進制setgidauth例如使用如下命令chgrpauthsubsysod2111為編譯本程序使用如下命令ccsubsys.c–lprot–lx–osubsys4-1subsys.c部分1/21SecureWare必須在可信任軟件的程序中定義如果在編譯行沒有定義那么就要有#defineSecureWare語句這樣使得頭文件中有關(guān)安全的定義可被正確地解釋行 pwd.h定義了passwd結(jié)構(gòu)可信任軟件使用這個信息來識別用戶如行 行21和 行23的例535strchr(S)string.h每個例程的幫助頁都定義了在調(diào)用這些例需要的#include行行 19main()中的第一個動作countvector兩參數(shù)調(diào)用此程序identity(S)幫助頁描述了set_auth_parameters()行20~28 這些行獲得了給命令行上帳戶名稱的/etc/passwd的如果沒有指定名稱就私有當(dāng)前的EUID 如果在/etc/passwd沒有即帳戶不存在就退出返回一錯誤消息注意當(dāng)程序報告帳戶不存在時沒有有關(guān)安全的因為你可以通過查看所有用戶都能查看的/etc/passwd文件來決定是否存在4-2subsys.c行29~33這些行檢查此用戶是否被看此帳戶的權(quán)限只有帳戶屬主匹配LUID的UID或帳戶管理員擁有auth子系統(tǒng)權(quán)限的用戶可以查看這個的權(quán)限一個未授4-2subsys.c行34~38 這些行報告帳戶名稱和人的真實假定是在第一個逗號前的/etc/passwd文件的pw_gecos域的部分行39~45 這些行獲得帳戶的子系統(tǒng)權(quán)限向量因為帳戶存在于/etc/passwd文件中它必須有一個受保護口令如果它不存在它是一個可審核的問題注意如果帳戶是通過客戶端模式NIS定義的這就不一定正確了但是它會隱瞞調(diào)用程序行41~43 audit_auth_entry(S)調(diào)用產(chǎn)生這種審核記錄第一個參數(shù)是/etc/passwd文件的用戶名稱第二個參數(shù)指定問題類型OT_PRPED是受保護口令數(shù)據(jù)庫參見audit.h文件中有效type標(biāo)志的列表第三個參數(shù)是記錄在審核數(shù)據(jù)庫中記錄的文字字符串參authaudit(S)中記錄其他類型審核記錄的例程列表46~51這些行獲得安裝子系統(tǒng)的名稱如果沒有被列出行47~49audit_ecurity_failure的第一個參數(shù)定義檢測到問題的對象OT_SUBSYS子系統(tǒng)數(shù)據(jù)庫參見audit.h頭文件中的有效值列表第二和第三個參數(shù)記錄期望和當(dāng)前的診斷問題的幫助值第四和第五參數(shù)識別關(guān)于此問題的附加信息在這些示例程序中信息是由英語寫的硬代碼如果你需要本地化你的應(yīng)用使用消息來實現(xiàn)這些消息行47~51以使這些消息顯示成用戶所用的語言52-58fg_cprivspr_passwd結(jié)構(gòu)中設(shè)置了帳戶就有一個子系統(tǒng)權(quán)限的私有列表如果沒有就應(yīng)用系統(tǒng)缺省的如果系統(tǒng)缺省列表不存在就沒有缺省權(quán)限在這種特殊情況下這不認(rèn)為是錯誤但是在大多數(shù)情況中這會被當(dāng)作需要審核的錯誤如果沒有缺省的權(quán)限就給權(quán)限賦一受限的值 prwarn.c程序在用戶口令到期時給出警告prwarn定在口令到期給出警告前的天數(shù)在警告期間的小時和分鐘數(shù)目和接收警告的用戶名稱此程序通常從用戶的.profile或.login警告適用于此用戶警告的存為$HOME/.prwarn_time文件的修改時間在系統(tǒng)的缺省設(shè)置下使用pr_paswd任何要查詢受保護口令數(shù)據(jù)庫的程序必須以auth的有效組IDEUID下執(zhí)行為了安裝本程序要生成二進制的setgidauth 例如使用如下命令chgrpauthprwarnod2111prwarnccprwarn.c–lprot–lx–o4-3prwarn.c1SecureWare必須在使用可信任軟件的程序里定義如果在編譯行沒有定義那么就要有#defineSecureWare語句這樣使得頭文件中有關(guān)安全的定義可被正確地解釋行5 因為代碼定義了可變長度參數(shù)列表的函數(shù)所以此頭文件是必須的行7~9這些行包括了定義了可信任設(shè)備的三個頭文件行 pwd.h定義了passwd結(jié)構(gòu)可信任軟件用此信息來識別用行 行行 部分缺省的程序選項參見defopen(S)行16~20這些全局的#define語句是為簡化而寫在此的但是在有幾個程序的應(yīng)用中應(yīng)該把這些定義放在應(yīng)用的頭文件里然后在應(yīng)用的所有程序里用#include語句包括行16~17 文字TRUE和FALSE是為了增加可讀性行18 ARBSTRSIZ在行83和298中使用行19~20 本程序的時間精度是秒定義這些時間的尺度常量增加了代碼的可讀性行21本行提供了對當(dāng)前日期和時間的time_t類型在/usr/include/sys/types.h文行22 如果LUID登陸用戶標(biāo)識是帳戶管理員本行為真行23 行 在報告間的缺省時間是六小時本程序以秒為時間的測量尺度通過把行中定義的常量乘上小時數(shù)在計算出報告的時間行47~49覆蓋這個缺省值行26 27~50這些行用標(biāo)準(zhǔn)字符串比較函數(shù)來分析<hhmm>45~46hourmins的值有效如果沒有返回用1標(biāo)志錯誤盡管這是一個致命錯誤但是本程序在這點不退出這個錯誤只有在用戶發(fā)出命令產(chǎn)生輸入錯誤時才發(fā)生當(dāng)調(diào)用這個例程行317時錯誤的返回導(dǎo)致調(diào)用定義在行272~291的usage例程usage顯示一個錯誤消息提示命令的正確語法然后退出4-5prwarn.c3/13行 行 部分行 部分行 這些行確定用戶最后一次被警告口令到期的日期和時行 不是 也是相對/119~120stat(S)st_mtime值是存行 這些行記住一個待定的截止期剛被報告此代碼假定當(dāng)前工 是 部分行134~147 作為無窮大解釋即口令行 4-9prwarn.c4-10prwarn.c162~175此代碼計算口令開始不能使用的日期或時間4-10prwarn.c184~199這些行決定口令是否現(xiàn)在就要改變?nèi)绻灰獎t為何不要CanBeChanged表示口令現(xiàn)在可以改變TooEarly表示口令現(xiàn)在不能改變因為離它上次改變的時間還不久Procrastinated表示口令早就該改了口令到期了但是還有CanBeChanged在行198259中用到TooEarly195中用到Procrastinated197262中用到192~193如果口令從沒設(shè)置過行194~195 如果從上次更改起時間少于行148~161中計算的最小更改時間行196~197如果口令有一有限的而且上次更改的時間早于行162~169中計算的日期口令就不能改變而且該用戶不能登陸198行200~213此代碼檢查當(dāng)前用戶LUID是否有權(quán)利改變此用戶的口令未的用戶沒有理由知道另一用戶的口令何時到期當(dāng)且僅當(dāng)運行本程序的用戶可以改變口令他才有權(quán)知道口令何時到期這個例程在行231中調(diào)用行 如果LUID有auth子系統(tǒng)權(quán)限口令可以改行 行 如果系統(tǒng)有一缺省的pswduser當(dāng)且僅當(dāng)LUID是系統(tǒng)的缺省口令才可以改變注意只有用戶沒有 行 4-11prwarn.c2124-11prwarn.c行 如果口令快到期了這些行就向用戶報行221~230 用戶有對/etc/passwd文件的所以沒有受保護口令也可以審231~237如果用戶無權(quán)改變口令顯示一錯誤消息authorized_to_change子例程在行200~213中定義4-12prwarn.c行238~239 用戶設(shè)置提示口令快到期的頻率如果此時間周期超過發(fā)送警告所用的時間就不發(fā)出警告且不更新上次警告的時間行 否則發(fā)出口令必須立刻改變的警告并且更新上次警告的時25577~110when子例程該子例程返回一個可讀的表示將來或過去的行259 行185定義了CanBeChanged情況行262 行187定義了Procrastinated情況268123~133just_reported例程該例程改變用戶.prwarn_time文件的4-13prwarn.c4-14prwarn.c行272~291 該子例程顯示使用消息并且如果用戶發(fā)出錯誤命令就退出程序它在行4-14prwarn.c行292 本行開始main()例程這樣所有子例程都作為main()調(diào)用的函數(shù)行299 set_auth_parameters(S)必須是main()中調(diào)用的第一個函數(shù)行300~301這些行初始化當(dāng)前日期和時間而且判定登陸用戶是否為帳戶管理員行302~308 如果有任何合法的系統(tǒng)缺省值就使用它們而不用程序內(nèi)部的缺省值25~26行309~323 如果在命令行提供了顯式的值檢查它們是否合法如果是這使用這些值而不用系統(tǒng)或程序缺省值行

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論