C語言深度剖析_第1頁
C語言深度剖析_第2頁
C語言深度剖析_第3頁
C語言深度剖析_第4頁
已閱讀5頁,還剩49頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

關(guān)鍵字C語言標(biāo)準(zhǔn)定義的32個關(guān)鍵字(下面是我不確定明白的)auto聲明自動變量,缺省時編譯器一般默認(rèn)為autoint聲明整型變量,編譯器在默認(rèn)的缺省情況下,所有變量都是auto的。double聲明雙精度變量long聲明長整型變量char聲明字符型變量float聲明浮點(diǎn)型變量short聲明短整型變量signed聲明有符號類型變量unsigned聲明無符號類型變量struct聲明結(jié)構(gòu)體變量union 聲明聯(lián)合數(shù)據(jù)類型enum 聲明枚舉類型default開關(guān)語句中的“其他”分支register聲明寄存器變量const 聲明只讀變量volatile說明變量在程序執(zhí)行中可被隱含地改變typedef用以給數(shù)據(jù)類型取別名(當(dāng)然還有其他作用)extern聲明變量是在其他文件正聲明(也可以看做是引用變量)return子程序返回語句(可以帶參數(shù),也可不帶參數(shù))void聲明函數(shù)無返回值或無參數(shù),聲明空類型指針goto無條件跳轉(zhuǎn)語句sizeof計算對象所占內(nèi)存空間大小什么是定義?什么是聲明?它們有何區(qū)別?舉個例子:A)inti;B)exteminti;(關(guān)于extern,后面解釋)什么是定義:所謂的定義就是(編譯器)創(chuàng)建一個對象,為這個對象分配ー塊內(nèi)存并給它取上一個名字,這個名字就是我們經(jīng)常所說的變量名或?qū)ο竺5⒁?這個名字一旦和這塊內(nèi)存匹配起來,它們就同生共死,終生不離不棄。并且這塊內(nèi)存的位置也不能被改變。ー個變量或?qū)ο笤谝欢ǖ膮^(qū)域內(nèi)(比如函數(shù)內(nèi),全局等)只能被定義一次,如果定義多次,編譯器會提示你重復(fù)定義同一個變量或?qū)ο?。什么是聲明:有兩重含義,如下:第一重含義:告訴編譯器,這個名字已經(jīng)匹配到ー塊內(nèi)存上了,下面的代碼用到變量或?qū)ο笫窃趧e的地方定義的。聲明可以出現(xiàn)多次。第二重含義:告訴編譯器,我這個名字我先預(yù)定了,別的地方再也不能用它來作為變量名或?qū)ο竺?。這種聲明最典型的例子就是函數(shù)參數(shù)的聲明,例如:A是定義;B)是聲明。定義聲明最重要的區(qū)別:定義創(chuàng)建了對象并為這個對象分配了內(nèi)存,聲明沒有分配內(nèi)存register:這個關(guān)鍵字請求編譯器盡可能的將變量存在CPU內(nèi)部寄存器中而不是通過內(nèi)存尋址訪問以提髙效率。注意是盡可能,不是絕對。你想想,一個CPU的寄存器也就那么幾個或幾十個,你要是定義了很多很多register變量,它累死也可能不能全部把這些變量放入寄存器吧,輪也可能輪不到你。數(shù)據(jù)從內(nèi)存里拿出來先放到寄存器,然后CPU再從寄存器里讀取數(shù)據(jù)來處理,處理完后同樣把數(shù)據(jù)通過寄存器存放到內(nèi)存里,CPu不直接和內(nèi)存打交道。這里要說明的一點(diǎn)是:寄存器沒這么自覺,它從不主動干什么事。那么ー個CPU也可以有很多寄存器,不同型號的CPU擁有寄存器的數(shù)量不一樣。為啥要這么麻煩啊?就是因?yàn)樗俣?。寄存器其?shí)就是ー塊一塊小的存儲空間,只不過其存取速度要比內(nèi)存快得多。進(jìn)水樓臺先得月嘛,它離CPU很近,CPU一伸手就拿到數(shù)據(jù)了,比在那么大的ー塊內(nèi)存里去尋找某個地址上的數(shù)據(jù)快多了

雖然寄存器的速度非???但是使用register修飾符也有些限制的:register變量必須是能被CPU寄存器所接受的類型。意味著register變量必須是ー個單個的值,并且其長度應(yīng)小于或等于整型的長度。而且register變量可能不存放在內(nèi)存中,所以不能用取址運(yùn)算符來獲取register變量的地址。不要誤以為關(guān)鍵字static很安靜,其實(shí)它一點(diǎn)也不安靜。這個關(guān)鍵字在C語言里主要有兩個作用,C++對它進(jìn)行了擴(kuò)展。第一個作用:修飾變量。變量又分為局部和全局變量,但它們都存在內(nèi)存的靜態(tài)區(qū)。靜態(tài)全局變量,作用域僅限于變量被定義的文件中,其他文件即使用extern聲明也沒法使用他。準(zhǔn)確地說作用域是從定義之處開始,到文件結(jié)尾處結(jié)束,在定義之處前面的那些代碼行也不能使用它。想要使用就得在前面再加extern***?惡心吧?要想不惡心,很簡單,直接在文件頂端定義不就得了。靜態(tài)局部變量,在函數(shù)體里面定義的,就只能在這個函數(shù)里用了,同一個文檔中的其他函數(shù)也用不了。由于被static修飾的變量總是存在內(nèi)存的靜態(tài)區(qū),所以即使這個函數(shù)運(yùn)行結(jié)束,這個靜態(tài)變量的值還是不會被銷毀,函數(shù)下次使用時仍然能用到這個值。第二個作用:修飾函數(shù)。函數(shù)前加static使得函數(shù)成為靜態(tài)函數(shù)。但此處“static”的含義不是指存儲方式,而是指對函數(shù)的作用域僅局限于本文件(所以又稱內(nèi)部函數(shù))。使用內(nèi)部函數(shù)的好處是:不同的人編寫不同的函數(shù)時,不用擔(dān)心自己定義的函數(shù),是否會與其它文件中的函數(shù)同名。關(guān)鍵字static有著不尋常的歷史。起初,在C中引入關(guān)鍵字static是為了表示退出ー個塊后仍然存在的局部變量。隨后,static在C中有了第二種含義:用來表示不能被其它文件訪問的全局變量和函數(shù)。為了避免引入新的關(guān)鍵字,所以仍使用static關(guān)鍵字來表示這第二種含義。當(dāng)然,C++里對static賦予了第三個作用,這double1.4,基本數(shù)據(jù)類型----short,int,long,char,短整型shortdouble短整型short。使用拼音。程序中的英文單詞一般不要太復(fù)雜,用詞應(yīng)當(dāng)準(zhǔn)確。C語言包含的數(shù)據(jù)類型如下我所示:,數(shù)値類型 C語言包含的數(shù)據(jù)類型如下我所示:,數(shù)値類型 <'Cく基本類型’I字符類型Cha數(shù)組2浩構(gòu)體struct。共用體union。校會類型enun指針桀型I空類型數(shù)據(jù)類型與“模子”short,int,long,char,float,double這六個關(guān)健字代表C語言里的六種基本數(shù)據(jù)類型。變量的命名規(guī)則一般規(guī)則:【規(guī)則1-1】命名應(yīng)當(dāng)直觀且可以拼讀,便于記憶和閱讀。標(biāo)識符最好采用英文單詞或其組合,不允許整?型p整型血メ士整型!ong*-1星請宴型floa雙精度型,doubleC三?=三型《 構(gòu)逛鋰!【規(guī)則1-2】命名的長度應(yīng)當(dāng)符合umin-length&&max-informationn原則。另外,英文詞盡量不縮寫,特別是非常用專業(yè)名詞,如果有縮寫,在同一系統(tǒng)中對同一単詞必須使用相同的表示法,并且注明其意思?!疽?guī)則1-3】當(dāng)標(biāo)識符由多個詞組成時,每個詞的第一個字母大寫,其余全部小寫。比如:【規(guī)則1イ】盡量避免名字中出現(xiàn)數(shù)字編號,如Valuel,Value2等,除非邏輯上的確需要編號。比如驅(qū)動開發(fā)時為管腳命名,非編號名字反而不好?!疽?guī)則1-5】對在多個文件之間共同使用的全局變量或函數(shù)要加范圍限定符(建議使用模塊名(縮寫)作為范圍限定符)。(GUI_,etc)【規(guī)則1-6】標(biāo)識符名分為兩部分:規(guī)范標(biāo)識符前綴(后綴)+含義標(biāo)識。非全局變量可以不用使用范圍限定符前綴?!疽?guī)則1-7】作用域前綴命名規(guī)則。No,標(biāo)識符類型作用域前綴GlobalVariablegFileStaticVariable(native)nFunctionStatic'VariablefAutoVariableaGlobalFunction gStaticFunction n【規(guī)則1-8】數(shù)據(jù)類型前綴命名規(guī)則。No.PrefixSuffixDataTypeExampleRemark1 bt bit BitbtVariable;b boolean booleanbVariable;c char charcVariable;i int intiVariable;s short[int] short[int]sVariable;I long[int] long[int]IVariablc;u unsigned[int]unsigned[int]uiVariable;d double doubledVariable;f floatfloat (Variable;ppointervoid*vpVariable;指針前綴vvoidvoidvVariable;st enum enumA stVariable;st struct structAstVariable;st union unionA stVariable;fp function point

18typed*structSM_Ev?ntOpt.18typed*structSM_Ev?ntOpt.<.當(dāng)自定義結(jié)構(gòu)數(shù)援類型時使用_st后亠?junst^iedchar*二:enumstractuunsignedint當(dāng)自定義_p*1nice.結(jié)構(gòu)數(shù)提char.類型為指}SMentOpJsfSNI_Ev st;針類型旳使用_ps,〇ニスJ.【規(guī)則1-9】含義標(biāo)識命名規(guī)則,變量命名使用名詞性詞組,函數(shù)命名使用動詞性詞組。例如:No變量名目標(biāo)詞動詞(的過去分詞)狀語目的地含義DataGotFromSDDataGotFromSD從SD中取得的數(shù)據(jù)DataDeletedFromSD DataDeletedFromSD從SD中刪除的數(shù)據(jù)變量含義標(biāo)識符構(gòu)成:目標(biāo)詞+動詞(的過去分詞)+[狀語]+[目的地];No變量名 動詞(的過去分詞) 目標(biāo)詞狀語目的地含義GetDataFromSDGetDataFrom SD從SD中取得數(shù)據(jù)DeleteDataFromSDDeleteDataFrom SD從SD中冊リ除數(shù)據(jù)函數(shù)含義標(biāo)識符構(gòu)成:動詞(一般現(xiàn)時)+目標(biāo)詞+[狀語]+[目的地];【規(guī)則1-10]程序中不得出現(xiàn)僅靠大小寫區(qū)分的相似的標(biāo)識符。例如:intx,X;變量x與X容易混淆這里還有一個要特別注意的就是1(數(shù)字1)和1(小寫字母1)之間,0(數(shù)字0)和。(小寫字母〇)之間的區(qū)別。這兩對真是很難區(qū)分的,我曾經(jīng)的ー個同事就被這個問題折騰了一次?!疽?guī)則1-11】ー個函數(shù)名禁止被用于其它之處?!疽?guī)則1-12】所有宏定義、枚舉常數(shù)、只讀變量全用大寫字母命名,用下劃線分割單詞。例如:constint MAX_LENGTH=100;〃這不是常量,而是一個只讀變量,具體請往后看#defineFILE_PATH“/usr/tmp”【規(guī)則1-13】考慮到習(xí)慣性問題,局部變量中可采用通用的命名方式,僅限于n、i、j等作為循環(huán)變量使用。一定不要寫出如下這樣的代碼:intp;chari;intc;char*a;一般來說習(xí)慣上用n,m,ij,k等表示int類型的變量:c,ch等表示字符類型變量:a等表示數(shù)組;P等表示指針。當(dāng)然這僅僅是一般習(xí)慣,除了ij,k等可以用來表示循環(huán)變量外,別的字符變量名盡量不要使用?!疽?guī)則1-14】定義變量的同時千萬千萬別忘了初始化。定義變量時編譯器并不一定清空了這塊內(nèi)存,它的值可能是無效的數(shù)據(jù)。這個問題在內(nèi)存管理那章有非常詳細(xì)的討論,請參看?!疽?guī)則1-15】不同類型數(shù)據(jù)之間的運(yùn)算要注意精度擴(kuò)展問題,一般低精度數(shù)據(jù)將向高精度數(shù)據(jù)擴(kuò)展。最冤枉的關(guān)鍵字ー---sizeof常年被人誤認(rèn)為函數(shù)sizeof是關(guān)鍵字不是函數(shù),其實(shí)就算不知道它是否為32個關(guān)鍵字之一時,我們也可以借助編譯器確定它的身份。記住:sizeof在計算變量所占空間大小時,括號可以省略,而計算類型(模子)大小時不能省略。一般情況下,咱也別偷這個懶,乖乖的寫上括號,繼續(xù)裝作一個“函數(shù)”,做ー個“披著函數(shù)皮的關(guān)鍵字”。sizeof(int)*p表示什么意思?留幾個問題(講解指針與數(shù)組時會詳細(xì)講解),32位系統(tǒng)下:int*p=NULL;sizeof(p)的值是多少?sizeofi(*p)呢?inta[100];sizeof(a)的值是多少?sizeof(a[100])呢?〃請尤其注意本例。sizeofi(&a)呢?sizeoR&a[〇])呢?intb[100];voidfun(intb[100]){sizeofifb);//sizeof(b)的值是多少?)1.4,signed、unsigned關(guān)鍵Y-我們知道計算機(jī)底層只認(rèn)識〇、1.任何數(shù)據(jù)到了底層都會變計算轉(zhuǎn)換成0、1.那負(fù)數(shù)怎么存儲呢?肯定這個“」號是無法存入內(nèi)存的,怎么辦?很好辦,做個標(biāo)記。把基本數(shù)據(jù)類型的最高位騰出來,用來存符號,同時約定如下:最高位如果是1,表明這個數(shù)是負(fù)數(shù),其值為除最高位以外的剩余位的值添上這個“二號;如果最高位是0,表明這個數(shù)是正數(shù),其值為除最高位以外的剩余位的值。這樣的話,ー個32位的signedint類型整數(shù)其值表示法范圍為:?231?231-1;8位的char類型數(shù)其值表示的范圍為?27?27J。一個32位的unsignedint類型整數(shù)其值表示法范圍為:0?232":8位的char類型數(shù)其值表示的范圍為0?28-1〇同樣我們的signed關(guān)鍵字也很寬恒大量,你也可以完全當(dāng)它不存在,編譯器缺省默認(rèn)情況下數(shù)據(jù)為signed類型的。上面的解釋很容易理解,下面就考慮一下這個問題:intmain()(chara[1000];inti;fbr(i=O;i<1000;i++)a[i]=-1-i;}printf(H%dM,strlen(a));return0;)此題看上去真的很簡單,但是卻鮮有人答對。答案是255。別驚訝,我們先分析分析。for循環(huán)內(nèi),當(dāng)i的值為0時,a[0]的值為ー1。關(guān)鍵就是ー1在內(nèi)存里面如何存儲。我們知道在計算機(jī)系統(tǒng)中,數(shù)值一律用補(bǔ)碼來表示(存儲)。主要原因是使用補(bǔ)碼,可以將符號位和其它位統(tǒng)ー處理;同時.,減法也可按加法來處理。另外,兩個用補(bǔ)碼表示的數(shù)相加時,如果最高位(符號位)有進(jìn)位,則進(jìn)位被舍棄。正數(shù)的補(bǔ)碼與其原碼一致;負(fù)數(shù)的ネト碼:符號位為1.其余位為該數(shù)絕對值的原碼按位取反,然后整個數(shù)加1。按照負(fù)數(shù)補(bǔ)碼的規(guī)則,可以知道一1的補(bǔ)碼為Oxff,-2的補(bǔ)碼為Oxfe 當(dāng)i的值為!27時,a[127]的值為ー128,而ー128是char類型數(shù)據(jù)能表示的最小的負(fù)數(shù)。當(dāng)i繼續(xù)增加,a[128]的值肯定不能是ー129。因?yàn)檫@時候發(fā)生了溢出,-129需要9位才能存儲下來,而char類型數(shù)據(jù)只有8位,所以最高位被丟棄。剩ド的8位是原來9位補(bǔ)碼的低8位的值,即Ox7f。當(dāng)i繼續(xù)增加到255的時候,-256的補(bǔ)碼的低8位為0。然后當(dāng)i增加到256時,-257的補(bǔ)碼的低8位全為1,即低八位的補(bǔ)碼為Oxff,如此又開始ー輪新的循環(huán)……按照上面的分析,a[0]到a[254]里面的值都不為0,而a[255]的值為0。strlen函數(shù)是計算字符串長度的,并不包含字符串最后的‘、?!?。而判斷ー個字符串是否結(jié)束的標(biāo)志就是看是否遇到‘、〇'。如果遇到,\o'I則認(rèn)為本字符串結(jié)束。分析到這里,strlen(a)的值為255應(yīng)該完全能理解了。這個問題的關(guān)鍵就是要明白char類型默認(rèn)情況下是有符號的,其表示的值的范圍為[-128,127],超出這個范圍的值會產(chǎn)生溢出。另外還要清楚的就是負(fù)數(shù)的補(bǔ)碼怎么表示。弄明白了這兩點(diǎn),這個問題其實(shí)就很簡單了。bool變量與“零值”進(jìn)行比較bool變量與“零值”進(jìn)行比較的if語句怎么寫?boolbTestFlag=FALSE;//想想為什么一般初始化為FALSE比較好?A),if(bTestFlag==0);if(bTestFlag=1);B),ififbTestFlag=TRUE);iRbTestFlag=FLASE);C),iflfbTestFlag);if(!bTestFlag);哪ー組或是那些組正確呢?我們來分析分析:A)寫法:bTestFlag是什么?整型變量?如果要不是這個名字遵照了前面的命名規(guī)范,肯怕很容易讓人誤會成整型變量。所以這種寫法不好。B)寫法:FLASE的值大家都知道,在編譯器里被定義為0;但TRUE的值呢?都是1嗎?很不幸,不都是1。VisualC++定義為!,而它的同胞兄弟VisualBasic就把TRUE定義為ー1.那很顯然,這種寫法也不好。大家都知道if語句是靠其后面的括號里的表達(dá)式的值來進(jìn)行分支跳轉(zhuǎn)的。表達(dá)式如果為真,則執(zhí)行if語句后面緊跟的代碼:否則不執(zhí)行。那顯然,本組的寫法很好,既不會引起誤會,也不會由于TRUE或FLASE的不同定義值而出錯。記?。阂院髮懘a就得這樣寫。float變量與“零值”進(jìn)行比較float變量與“零值”進(jìn)行比較的if語句怎么寫?floatfTestVal=0.0:A),if(fTestVal==0.0);if|fTestVal!=0.0);B),if|(fTestVal>=-EPSINON)&&(fTestVal<=EPSINON));//EPSINON為定義好的精度。哪ー組或是那些組正確呢?我們來分析分析:float和double類型的數(shù)據(jù)都是有精度限制的,這樣直接拿來與0.0比,能正確嗎?明顯不能,看例子:的值四舍五入精確到小數(shù)點(diǎn)后!0位為:3.1415926536,你拿它減去0.00000000001然后再四舍五入得到的結(jié)果是多少?你能說前后兩個值ー樣嗎?EPSINON為定義好的精度,如果ー個數(shù)落在[0.0-EPS1NONOO+EPSINON]這個閉區(qū)間內(nèi),我們認(rèn)為在某個精度內(nèi)它的值與零值相等;否則不相等。擴(kuò)展一下,把0.0替換為你想比較的任何ー個浮點(diǎn)數(shù),那我們就可以比較任意兩個浮點(diǎn)數(shù)的大小了,當(dāng)然是在某個精度內(nèi)。同樣的也不要在很大的浮點(diǎn)數(shù)和很小的浮點(diǎn)數(shù)之間進(jìn)行運(yùn)算,比如:10000000000.00+0.00000000001這樣計算后的結(jié)果可能會讓你大吃ー驚。指針變量與“零值”進(jìn)行比較指針變量與“零值”進(jìn)行比較的if語句怎么寫?int*p=NULL;//定義指針一定要同時初始化,指針與數(shù)組那章會詳細(xì)講解。A),if(p=O);if(p!=〇);B),if(p);if(!p);C),ififNULL=p);if(NULL!=p);哪ー組或是那些組正確呢?我們來分析分析:A)寫法:p是整型變量?容易引起誤會,不好。盡管NULL的值和0ー樣,但意義不同。B)寫法:p是bool型變量?容易引起誤會,不好。C)寫法:這個寫法オ是正確的,但樣子比較古怪。為什么要這么寫呢?是怕漏寫ー個“=”號:if(p=NULL),這個表達(dá)式編譯器當(dāng)然會認(rèn)為是正確的,但卻不是你要表達(dá)的意思。所以,非常推薦這種寫法。Case語句記?。篹ase后面只能是整型或字符型的常量或常量表達(dá)式(想想字符型數(shù)據(jù)在內(nèi)存里是怎么存的)?!窘ㄗh1-27]在多重:循環(huán)中,如果有可能,應(yīng)當(dāng)將最長的循環(huán)放在最內(nèi)層,最短的循環(huán)放在最外層,以減少CPU跨切循環(huán)層的次數(shù)?!窘ㄗh1-28】建議for語句的循環(huán)控制變量的取值采用“半開半閉區(qū)間”寫法。半開半閉區(qū)間寫法和閉區(qū)間寫法雖然功能是相同,但相比之下,半開半閉區(qū)間寫法寫法更加直觀?!疽?guī)則1-29]不能在for循環(huán)體內(nèi)修改循環(huán)變量,防止循環(huán)失控?!疽?guī)則1-30】循環(huán)要盡可能的短,要使代碼淸晰,一目了然。如果你寫的ー個循環(huán)的代碼超過ー顯示屏,那會讓讀代碼的人發(fā)狂的。解決的辦法由兩個:第一,重新設(shè)計這個循環(huán),確認(rèn)是否這些操作都必須放在這個循環(huán)里;第二,將這些代碼改寫成一個子函數(shù),循環(huán)中只調(diào)用這個子函數(shù)即可。一般來說循環(huán)內(nèi)的代碼不要超過20行?!疽?guī)則1-31】把循環(huán)嵌套控制在3層以內(nèi)。國外有研究數(shù)據(jù)表明,當(dāng)循環(huán)嵌套超過3層,程序員對循環(huán)的理解能力會極大的降低。如果你的循環(huán)嵌套超過3層,建議你重新設(shè)計循環(huán)或是將循環(huán)內(nèi)的代碼改寫成?個字函數(shù)。一般來說,編碼的水平與goto語句使用的次數(shù)成反比。有的人主張慎用但不禁用goto語句,但我主張禁用?!疽?guī)則1-32】禁用goto語句。自從提倡結(jié)構(gòu)化設(shè)計以來,goto就成了有爭議的語句。首先,由于goto語句可以靈活跳轉(zhuǎn),如果不加限制,它的確會破壞結(jié)構(gòu)化設(shè)計風(fēng)格;其次,goto語句經(jīng)常帶來錯誤或隱患。它可能跳過了變量的初始化、重要的計算等語句,void的字面意思是“空類型",void?則為“空類型指針”,void?可以指向任何類型的數(shù)據(jù)。void幾乎只有“注釋”和限制程序的作用,因?yàn)閺膩頉]有人會定義ー個void變量,看看下面的例子:voida;VisualC++6.0上,這行語句編譯時會出錯,提示“illegaluseoftype'void”‘。不過,即使voida的編譯不會出錯,它也沒有任何實(shí)際意義。void真正發(fā)揮的作用在于;對函數(shù)返回的限定;對函數(shù)參數(shù)的限定。眾所周知,如果指針pl和p2的類型相同,那么我們可以直接在pl和P2間互相賦值;如果pl和P2指向不同的數(shù)據(jù)類型,則必須使用強(qiáng)制類型轉(zhuǎn)換運(yùn)算符把賦值運(yùn)算符右邊的指針類型轉(zhuǎn)換為左邊指針的類型。例如;float*pl;int*p2;pl=p2;其中pl=p2語句會編譯出錯,提示"'=':cannotconvertfrom'int*'to'float*'”,必須改為:pl=(float*)p2;而void?則不同,任何類型的指針都可以直接賦值給它,無需進(jìn)行強(qiáng)制類型轉(zhuǎn)換;void*pl;int*p2;pl=p2;但這并不意味著,void?也可以無需強(qiáng)制類型轉(zhuǎn)換地賦給其它類型的指針。因?yàn)椤翱疹愋汀笨梢园荨坝蓄愋汀?,而“有類型”則不能包容“空類型”。比如,我們可以說“男人和女人都是人”,但不能說“人是男人”或者“人是女人”。下面的語句編譯出錯;void*pl;int*p2;p2=pl;提示“'=':cannotconvertfrom'void*'to'int*'”.1.10.2,void修飾函數(shù)返回值和參數(shù)【規(guī)則1-33】如果函數(shù)沒有返回值,那么應(yīng)聲明為void類型在C語言中,凡不加返回值類型限定的函數(shù),就會被編譯器作為返回整型值處理。但是許多程序員卻誤以為其為void類型。為了避免混亂,我們在編寫C程序時,對于任何函數(shù)都必須ー個不漏地指定其類型。如果函數(shù)沒有返回值,一定要聲明為void類型。這既是程序良好可讀性的需要,也是編程規(guī)范性的要求。另タト,加上void類型聲明后,也可以發(fā)揮代碼的“自注釋”作用。所謂的代碼的“自注釋”即代碼能自己注釋自己?!疽?guī)則1-34]如果函數(shù)無參數(shù),那么應(yīng)聲明其參數(shù)為void在C++中,函數(shù)參數(shù)為void的意思是這個函數(shù)不接受任何參數(shù)。在c語言中,可以給無參數(shù)的函數(shù)イ專送任意類型的參數(shù),但是在C++編譯器中編譯同樣的代碼則會出錯。在C++中,不能向無參數(shù)的函數(shù)傳送任何所以,無論在C還是C++中,若函數(shù)不接受任何參數(shù),一定要指明參數(shù)為void0【規(guī)則1-35]千萬小心又小心使用void指針類型。按照ANSI(AmericanNationalStandardsInstitute)標(biāo)準(zhǔn),不能対void指針進(jìn)行算法操作,即下列操作都是不合法的:void*pvoid;pvoid++;//ANSI:錯誤pvoid+=1;//ANSI:錯誤ANSI標(biāo)準(zhǔn)之所以這樣認(rèn)定,是因?yàn)樗鼒猿郑哼M(jìn)行算法操作的指針必須是確定知道其指向數(shù)據(jù)類型大小的。也就是說必須知道內(nèi)存冃的地址的確切值。例如:int*pint;pint++;//ANSI:正確但是大名鼎鼎的GNU(GNU'sNotUnix的遞歸縮寫)則不這么認(rèn)定,它指定void?的算法操作與char*一致。因此下列語句在GNU編譯器中皆正確:pvoid++;//GNU:正確pvoid+=1;//GNU:正確在實(shí)際的程序設(shè)計中,為符合ANSI標(biāo)準(zhǔn),并提高程序的可移植性,我們可以這樣編寫實(shí)現(xiàn)同樣功能的代碼:void*pvoid;(char*)pvoid++;//ANSI:正確;GNU:正確(char*)pvoid+=1;//ANSI:錯誤;GNU:正確GNU和ANSI還有一些區(qū)別,總體而言,GNU較ANSI更“開放”,提供了對更多語法的支持。但是我們在真實(shí)設(shè)計時,還是應(yīng)該盡可能地符合ANSI標(biāo)準(zhǔn)?!疽?guī)則1-36]如果函數(shù)的參數(shù)可以是任意類型指針,那么應(yīng)聲明其參數(shù)為void*o典型的如內(nèi)存操作函數(shù)memcpy和memset的函數(shù)原型分別為:void*memcpy(void*dest,constvoid*src,size_tlen);void*memset(void*buffer,intc,sizetnum);這樣,任何類型的指針都可以傳入memcpy和memset中,這也真實(shí)地體現(xiàn)了內(nèi)存操作函數(shù)的意義,因?yàn)樗僮鞯膶ο髢H僅是一片內(nèi)存,而不論這片內(nèi)存是什么類型。如果memcpy和memset的參數(shù)類型不是void*,而是char*,那オ叫真的奇怪了!這樣的memcpy和memset明顯不是ー個“純粹的,脫離低級趣味的”函數(shù)!下面的代碼執(zhí)行正確:例子:memset接受任意類型指針intIntArray_a[100];memset(IntArray_a,0,100*sizeof(int));//將IntArraya清0例子:memcpy接受任意類型指針intdestintArray_a[100],srcintarray_a[100];〃將srcintarraya拷貝給destlntArrayamemcpy(destIntArray_a,srcintarray_a,100*sizeof(int));有趣的是,memcpy和memset函數(shù)返回的也是void?類型,標(biāo)準(zhǔn)庫函數(shù)的編寫者都不是一般人?!疽?guī)則1-37】void不能代表ー個真實(shí)的變量。因?yàn)槎x變量時必須分配內(nèi)存空間,定義void類型變量,編譯器到底分配多大的內(nèi)存呢。卜.面代碼都企圖讓void代表ー個真實(shí)的變量,因此都是錯誤的代碼:voida;〃錯誤fiinction(voida);〃錯誤void體現(xiàn)了一種抽象,這個世界上的變量都是‘’有類型”的,譬如一個人不是男人就是女人(人妖不算)。void的出現(xiàn)只是為了一種抽象的需要,如果你正確地理解了面向?qū)ο笾小俺橄蠡悺钡母拍?,也很容易理解void數(shù)據(jù)類型。正如不能給抽象基類定義ー個實(shí)例,我們也不能定義ー個void(讓我們類比的稱void為“抽象數(shù)據(jù)類型”)變量。void簡單吧?到底是“色”還是“空”呢?return關(guān)鍵字return用來終止一個函數(shù)并返回其后面跟著的值。char*Func(void)(Charstr[30];Returnstr;)str屬于局部變量,位于棧內(nèi)存中,在Func結(jié)束的時候被釋放,所以返回str將導(dǎo)致錯誤?!疽?guī)則1-38]return語句不可返回指向''棧內(nèi)存”的“指針”,因?yàn)樵搩?nèi)存在函數(shù)體結(jié)束時被自動銷毀。const關(guān)鍵字也許該被替換為readolnyconst是constant的縮寫,是恒定不變的意思,也翻譯為常量、常數(shù)等。很不幸,正是因?yàn)檫@一點(diǎn),很多人都認(rèn)為被const修飾的值是常量。這是不精確的,精確的說應(yīng)該是只讀的變量,其值在編譯時不能被使用,因?yàn)榫幾g器在編譯時不知道其存儲的內(nèi)容?;蛟S當(dāng)初這個關(guān)鍵字應(yīng)該被替換為readonly?那么這個關(guān)鍵字有什么用處和意義呢?const推出的初始目的,正是為了取代預(yù)編譯指令,消除它的缺點(diǎn),同時繼承它的優(yōu)點(diǎn)。我們看看它與define宏的區(qū)別。(很多人誤以為define是關(guān)鍵字,在這里我提醒你再回到本章前面看看32個關(guān)鍵字里是否有define)〇const修飾的只讀變量定義const只讀變量,具有不可變性。例如:constintMax=100;intArray[Max];這里請在VisualC++6.0里分別創(chuàng)建.c文件和.cpp文件測試ー下。你會發(fā)現(xiàn)在.c文件中,編譯器會提示出錯,而在.cpp文件中則順利運(yùn)行。為什么呢?我們知道定義ー個數(shù)組必須指定其元素的個數(shù)。這也從側(cè)面證實(shí)在C語言中,const修飾的Max仍然是變量,只不過是只讀屬性罷了:而在C++里,擴(kuò)展了const的含義,這里就不討論了。注意:const修飾的只讀變量必須在定義的同時初始化,想想為什么?留一個問題:case語句后面是否可以是const修飾的只讀變量呢?請動手測試一下。節(jié)省空間,避免不必要的內(nèi)存分配,同時提高效率編譯器通常不為普通const只讀變量分配存儲空間,而是將它們保存在符號表中,這使得它成為ー個編譯期間的值,沒有了存儲與讀內(nèi)存的操作,使得它的效率也很高。例如:#defineM3〃宏常量constintN=5;〃此時并未將N放入內(nèi)存中inti=N;〃此時為N分配內(nèi)存,以后不再分配!intI=M;〃預(yù)編譯期間進(jìn)行宏替換,分配內(nèi)存intj=N;〃沒有內(nèi)存分配intJ=M;〃再進(jìn)行宏替換,又一次分配內(nèi)存!const定義的只讀變量從匯編的角度來看,只是給出了對應(yīng)的內(nèi)存地址,而不是象#define一樣給出的是立即數(shù),所以,const定義的只讀變量在程序運(yùn)行過程中只有一份拷貝(因?yàn)樗侨值闹蛔x變量,存放在靜態(tài)區(qū)),而#define定義的宏常量在內(nèi)存中有若干個拷貝。#define宏是在預(yù)編譯階段進(jìn)行替換,而const修飾的只讀變量是在編譯的時候確定其值。#define宏沒有類型,而const修飾的只讀變量具有特定的類型。修飾一般變量一般常量是指簡單類型的只讀變量。這種只讀變量在定義時,修飾符const可以用在類型說明符前,也可以用在類型說明符后。例如:intconsti=2;或constinti=2;修飾數(shù)組定義或說明一個只讀數(shù)組可采用如下格式:intconsta[5]={l,2,3,4,5};或constinta[5]={1,2,3,4,5};修飾指針constint*p; //p可變,p指向的對象不可變intconst*p; //p可變,p指向的対象不可變int?constp;//p不可變,p指向的對象可變constint*constp;〃指針p和p指向的對象都不可變在平時的授課中發(fā)現(xiàn)學(xué)生很難記住這幾種情況。這里給出ー個記憶和理解的方法:先忽略類型名(編譯器解析的時候也是忽略類型名),我們看const離哪個近?!敖畼桥_先得月”,離誰近就修飾誰。constint*p;"const修飾?p,p是指針,*p是指針指向的對象,不可變intconst*p;"const修飾?p,p是指針,*p是指針指向的對象,不可變int*constp;"const修飾p,p不可變,p指向的對象可變constint*constp;//前ー個const修飾?p,后ー個const修飾p,指針p和p指向的對象都不可變1.11.6,修飾函數(shù)的參數(shù)const修飾符也可以修飾函數(shù)的參數(shù),當(dāng)不希望這個參數(shù)值被函數(shù)體內(nèi)意外改變時使用。例如:voidFun(constinti);告訴編譯器i在函數(shù)體中的不能改變,從而防止了使用者的ー些無意的或錯誤的修改。修飾函數(shù)的返回值const修飾符也可以修飾函數(shù)的返回值,返回值不可被改變。例如:constintFun(void);在另ー連接文件中引用const只讀變量:externconstinti;"正確的聲明externconstintj=10;//錯誤!只讀變量的值不能改變。注意這里是聲明不是定義,關(guān)于聲明和定義的區(qū)別,請看本章開始處。講了這么多講完了嗎?遠(yuǎn)沒有。在C++里,對const做了進(jìn)ー步的擴(kuò)展,還有很多知識未能最易變的關(guān)鍵字一一volatilevolatile是易變的、不穩(wěn)定的意思。很多人根本就沒見過這個關(guān)鍵字,不知道它的存在。也有很多程序員知道它的存在,但從來沒用過它。我對它有種“楊家有女初長成,養(yǎng)在深閨人未識”的感覺。volatile關(guān)鍵字和constー樣是ー種類型修飾符,用它修飾的變量表示可以被某些編譯器未知的因素更改,比如操作系統(tǒng)、硬件或者其它線程等。遇到這個關(guān)鍵字聲明的變量,編譯器對訪問該變量的代碼就不再進(jìn)行優(yōu)化,從而可以提供對特殊地址的穩(wěn)定訪問。先看看下面的例子:inti=10;intj=i;"(1)語句intk=i:"(2)語句這時候編譯器對代碼進(jìn)行優(yōu)化,因?yàn)樵冢?)、(2)兩條語句中,i沒有被用作左值。這時候編譯器認(rèn)為i的值沒有發(fā)生改變,所以在(1)語句時從內(nèi)存中取出i的值賦給j之后,這個值并沒有被丟掉,而是在(2)語句時繼續(xù)用這個值給k賦值。編譯器不會生成出匯編代碼重新從內(nèi)存里取i的值,這樣提高了效率。但要注意:(1)、(2)語句之間i沒有被用作左值オ行。再看另ー個例子:volatileinti=10;intj=i;〃(3)語句intk=i!〃(4)語句volatile關(guān)鍵字告訴編譯器i是隨時可能發(fā)生變化的,每次使用它的時候必須從內(nèi)存中取出i的值,因而編譯器生成的匯編代碼會重新從i的地址處讀取數(shù)據(jù)放在k中。這樣看來,如果i是ー個寄存器變量或者表示一個端口數(shù)據(jù)或者是多個線程的共享數(shù)據(jù),就容易出錯,所以說volatile可以保證對特殊地址的穩(wěn)定訪問。但是注意:在VC++6.0中,一般Debug模式?jīng)]有進(jìn)行代碼優(yōu)化,所以這個關(guān)鍵字的作用有可能看不出來。你可以同時生成Debug版和Release版的程序做個測試。留一個問題:constvolatileinti=10;這行代碼有沒有問題?如果沒有,那i到底是什么屬性?1.13I最會帶帽子的關(guān)鍵字----externextern,外面的、外來的意思。那它有什么作用呢?舉個例子:假設(shè)你在大街上看到一個黑皮膚綠眼睛紅頭發(fā)的美女(外星人?)或者帥哥。你的第一反應(yīng)就是這人不是國產(chǎn)的。extern就相當(dāng)于他們的這些區(qū)別于中國人的特性。extern可以置于變量或者函數(shù)前,以標(biāo)示變量或者函數(shù)的定義在別的文件中,下面的代碼用到的這些變量或函數(shù)是外來的,不是本文件定義的,提示編譯器遇到此變量和函數(shù)時在其他模塊中尋找其定義。就好比在本文件中給這些外來的變量或函數(shù)帶了頂帽子,告訴本文件中所有代碼,這些家伙不是土著。那你想想extern修飾的變量或函數(shù)是定義還是聲明?看列子:A.c文件中定義:B.c文件中用extern修飾:inti=10:externinti;〃寫成i=10:行嗎?voidfun(void)externvoidfun(void);//兩個void可否省略?{//code)C.h文件中定義;D.c文件中用extern修飾;intj=1;externdoublej;〃這樣行嗎?為什么?intk=2;j=3.0;〃這樣行嗎?為什么?至于externuCn的用法,一一般認(rèn)為屬于C++的范疇,這里就先不討論。當(dāng)然關(guān)于extern的討論還遠(yuǎn)沒有結(jié)束,在指針與數(shù)組那一章,你還會和它親密接觸的。struct關(guān)鍵字struct是個神奇的關(guān)鍵字,它將一些相關(guān)聯(lián)的數(shù)據(jù)打包成一個整體,方便使用。在網(wǎng)絡(luò)協(xié)議、通信控制、嵌入式系統(tǒng)、驅(qū)動開發(fā)等地方,我們經(jīng)常要傳送的不是簡單的字節(jié)流(char型數(shù)組),而是多種數(shù)據(jù)組合起來的一個整體,其表現(xiàn)形式是一個結(jié)構(gòu)體。經(jīng)驗(yàn)不足的開發(fā)人員往往將所有需要傳送的內(nèi)容依順序保存在char型數(shù)組中,通過指針偏移的方法傳送網(wǎng)絡(luò)報文等信息。這樣做編程復(fù)雜,易出錯,而且一旦控制方式及通信協(xié)議有所變化,程序就要進(jìn)行非常細(xì)致的修改,非常容易出錯。這個時候只需要一個結(jié)構(gòu)體就能搞定。平時我們要求函數(shù)的參數(shù)盡量不多于4個,如果函數(shù)的參數(shù)多于4個使用起來非常容易出錯(包括毎個參數(shù)的意義和順序都容易弄錯),效率也會降低(與具體CPU有關(guān),ARM芯片對于超過4個參數(shù)的處理就有講究,具體請參考相關(guān)資料)。這個時候,可以用結(jié)構(gòu)體壓縮參數(shù)個數(shù)??战Y(jié)構(gòu)體多大?結(jié)構(gòu)體所占的內(nèi)存大小是其成員所占內(nèi)存之和(關(guān)于結(jié)構(gòu)體的內(nèi)存對齊,請參考預(yù)處理那章)。這點(diǎn)很容易理解,但是下面的這種情況呢?Studentstudent}stu;sizeof(stu)的值是多少呢?在VisualC++6.0上測試一下。很遺憾,不是0,而是1〇為什么呢?你想想,如果我們把structstudent看成一個模子的話,你能造出ー個沒有任何容積的模子嗎?顯然不行。編譯器也是如此認(rèn)為。編譯器認(rèn)為任何?種數(shù)據(jù)類型都有其大小,用它來定義ー個變量能夠分配確定大小的空間。既然如此,編譯器就理所當(dāng)然的認(rèn)為任何ー個結(jié)構(gòu)體都是有大小的,哪怕這個結(jié)構(gòu)體為空。那萬一結(jié)構(gòu)體真的為空,它的大小為什么值比較合適呢?假設(shè)結(jié)構(gòu)體內(nèi)只有一個char型的數(shù)據(jù)成員,那其大小為Ibyte(這里先不考慮內(nèi)存對齊的情況),也就是說非空結(jié)構(gòu)體類型數(shù)據(jù)最少需要占ー個字節(jié)的空間,而空結(jié)構(gòu)體類型數(shù)據(jù)總不能比最小的非空結(jié)構(gòu)體類型數(shù)據(jù)所占的空間大吧。這就麻煩了,空結(jié)構(gòu)體的大小既不能為0,也不能大于1,怎么辦?定義為0.5個byte?但是內(nèi)存地址的最小單位是1個byte,0.5個byte怎么處理?解決這個問題的最好辦法就是折中,編譯器理所當(dāng)然的認(rèn)為你構(gòu)造ー個結(jié)構(gòu)體數(shù)據(jù)類型是用來打包ー些數(shù)據(jù)成員的,而最小的數(shù)據(jù)成員需要1個byte,編譯器為每個結(jié)構(gòu)體類型數(shù)據(jù)至少預(yù)留1個byte的空間。所以,空結(jié)構(gòu)體的大小就定位1個byte〇性數(shù)組也許你從來沒有聽說過柔性數(shù)組(flexiblearray)這個概念,但是它確實(shí)是存在的。C99中,結(jié)構(gòu)中的最后ー個元素允許是未知大小的數(shù)組,這就叫做柔性數(shù)組成員,但結(jié)構(gòu)中的柔性數(shù)組成員前面必須至少ー個其他成員。柔性數(shù)組成員允許結(jié)構(gòu)中包含ー個大小可變的數(shù)組。sizeof返回的這種結(jié)構(gòu)大小不包括柔性數(shù)組的內(nèi)存。包含柔性數(shù)組成員的結(jié)構(gòu)用malloc()函數(shù)進(jìn)行內(nèi)存的動態(tài)分配,并且分配的內(nèi)存應(yīng)該大于結(jié)構(gòu)的大小,以適應(yīng)柔性數(shù)組的預(yù)期大小。柔性數(shù)組到底如何使用呢?看下面例子:typedefstructst_type(inti;inta[0];}type_a;有些編譯器會報錯無法編譯可以改成:typedefstructst_type(inti;inta[];}type_a;這樣我們就可以定義ー個可變長的結(jié)構(gòu)體,用sizeof(type_a)得到的只有4,就是sizeoRi尸sizeoRint)。那個0個元素的數(shù)組沒有占用空間,而后我們可以進(jìn)行變長操作了。通過如下表達(dá)式給結(jié)構(gòu)體分配內(nèi)存:typea*p=(type_a*)malloc(sizeof(type_a)+100*sizeof(int));這樣我們?yōu)榻Y(jié)構(gòu)體指針p分配了一塊內(nèi)存。用p->item[n]就能簡單地訪問可變長元素。但是這時候我們再用sizeof(*p)測試結(jié)構(gòu)體的大小,發(fā)現(xiàn)仍然為4。是不是很詭異?我們不是給這個數(shù)組分配了空間么?別急,先回憶一下我們前面講過的“模子”。在定義這個結(jié)構(gòu)體的時候,模子的大小就已經(jīng)確定不包含柔性數(shù)組的內(nèi)存大小。柔性數(shù)組只是編外人員,不占結(jié)構(gòu)體的編制。只是說在使用柔性數(shù)組時需要把它當(dāng)作結(jié)構(gòu)體的ー個成員,僅此而已。再說白點(diǎn),柔性數(shù)組其實(shí)與結(jié)構(gòu)體沒什么關(guān)系,只是“掛羊頭賣狗肉”而已,算不得結(jié)構(gòu)體的正式成員。需要說明的是:C89不支持這種東西,C99把它作為ー種特例加入了標(biāo)準(zhǔn)。但是,C99所支持的是incompletetype,而不是zeroarray,形同intitem⑼;這種形式是非法的,C99支持的形式是形同intitem[];只不過有些編譯器把intitem⑼;作為非標(biāo)準(zhǔn)擴(kuò)展來支持,而且在C99發(fā)布之前已經(jīng)有了這種非標(biāo)準(zhǔn)擴(kuò)展了,C99發(fā)布之后,有些編譯器把兩者合而為ー了。當(dāng)然,上面既然用malloc函數(shù)分配了內(nèi)存,肯定就需要用free函數(shù)來釋放內(nèi)存:free(p);經(jīng)過上面的講解,相信你已經(jīng)掌握了這個看起來似乎很神秘的東西。不過實(shí)在要是沒掌握也無所謂,這個東西實(shí)在很少用。struct與class的區(qū)別在C++里struct關(guān)鍵字與class關(guān)鍵字一般可以通用,只有一個很小的區(qū)別。struct的成員默認(rèn)情況下屬性是public的,而class成員卻是private的。很多人覺得不好記,其實(shí)很容易。你平時用結(jié)構(gòu)體時用public修飾它的成員了嗎?既然struct關(guān)鍵字與class關(guān)鍵字可以通用,你也不要認(rèn)為結(jié)構(gòu)體內(nèi)不能放函數(shù)了。當(dāng)然,關(guān)于結(jié)構(gòu)體的討論遠(yuǎn)沒有結(jié)束,在指針與數(shù)組那一章,你還會要和它打交道的。1.15,union關(guān)鍵字union關(guān)鍵字的用法與struct的用法非常類似。union維護(hù)足夠的空間來置放多個數(shù)據(jù)成員中的“一種”,而不是為每ー個數(shù)據(jù)成員配置空間,在union中所有的數(shù)據(jù)成員共用一個空間,同一時間只能儲存其中一個數(shù)據(jù)成員,所有的數(shù)據(jù)成員具有相同的起始地址。例子如下:unionStateMachine(charcharacter;intnumber;char*str;doubleexp;}ー個union只配置ー個足夠大的空間以來容納最大長度的數(shù)據(jù)成員,以上例而言,最大長度是double型態(tài),所以StateMachine的空間大小就是double數(shù)據(jù)類型的大小。在C++里,union的成員默認(rèn)屬性頁為public。union主要用來壓縮空間。如果?一些數(shù)據(jù)不可能在同一時間同時被用到,則可以使用union。,大小端模式對union類型數(shù)據(jù)的影響下面再看ー個例子:union(inti;chara[2];}*p,u;p=&u;p->a[0]=0x39;p->a[l]=Ox38;p.i的值應(yīng)該為多少呢?這里需要考慮存儲模式:大端模式和小端模式。大端模式(Big-endian):字?jǐn)?shù)據(jù)的高字節(jié)存儲在低地址中,而字?jǐn)?shù)據(jù)的低字節(jié)則存放在高地址中。小端模式(Littljendian):字?jǐn)?shù)據(jù)的高字節(jié)存儲在高地址中,而字?jǐn)?shù)據(jù)的低字節(jié)則存放在低地址中。union型數(shù)據(jù)所金的空間等于其最大的成員所占的空間。對union型的成員的存取都是相對于該聯(lián)合體基地址的偏移量為0處開始,也就是聯(lián)合體的訪問不論對哪個變量的存取都是從union的首地址位置開始。如此一解釋,上面的問題是否已經(jīng)有了答案呢?,如何用程序確認(rèn)當(dāng)前系統(tǒng)的存儲模式?上述問題似乎還比較簡單,那來個有技術(shù)含量的:請寫一個C函數(shù),若處理器是Bigendian的,則返回0!若是Littleendian的,則返回1。先分析一下,按照上面關(guān)于大小端模式的定義,假設(shè)int類型變量i被初始化為1〇以大端模式存儲,其內(nèi)存布局如下圖:intis1;大端模式0x0 0x00x00x1高地址以小端模式存儲,其內(nèi)存布局如下圖:變量i占4個字節(jié),但只有一個字節(jié)的值為1,另外三個字節(jié)的值都為0。如果取出低地址上的值為0,毫無疑問,這是大端模式;如果取出低地址上的值為!,毫無疑問,這是小端模式。既然如此,我們完全可以利用union類型數(shù)據(jù)的特點(diǎn):所有成員的起始地址一致。到現(xiàn)在,應(yīng)該知道怎么寫了吧?參考答案如下:

intchcckSystem()unioncheck{inti;charch;}c;c.i=1;return(c.ch=1);)現(xiàn)在你可以用這個函數(shù)來測試你當(dāng)前系統(tǒng)的存儲模式了。當(dāng)然你也可以不用函數(shù)而直接去查看內(nèi)存來確定當(dāng)前系統(tǒng)的存儲模式。如下圖:■eaory ?Address:|0x12ff200012FF20Cfll>00000012FF20Cfll>00000080FF12000012FF283DB84000000000000012FF3O000000000050FD7F0012FF38CCCCCCCCCCCCCCCC0012FF40CCCCCCCCCCCCCCCC0012FF48CCCCCCCCCCCCCCCC0012FF50CCCCCCCCCCCCCCCC0012FF58CCCCCCCCCCCCCCCC0012FF60CCCCCCCCCCCCCCCC0012FF68CCCCCCCCCCCCCCCC0O12FF70CCCCCCCCCCCCCCCC圖中0x01的值存在低地址上,說明當(dāng)前系統(tǒng)為小端模式。不過要說明的一點(diǎn)是,某些系統(tǒng)可能同時支持這兩種存儲模式,你可以用硬件跳線或在編譯器的選項(xiàng)中設(shè)置其存儲模式。留個問題:在x86系統(tǒng)下,輸出的值為多少?#include<stdio.h>intmain()(inta[5]={1,2,345};int*ptrl=(int*)(&a+l);int*ptr2=(int*)((int)a+l);printff%x,%x”,ptrl[?l],*ptr2);return0;}enum關(guān)鍵字很多初學(xué)者對枚舉(enum)感到迷惑,或者認(rèn)為沒什么用,其實(shí)枚舉(enum)是個很有用的數(shù)據(jù)類型。枚舉類型的使用方法一般的定義方式如下:enumenum_typename(ENUM_CONST_1,ENUM_CONST_2,...ENUMCONSTn

}cnumvariablcname;注意:enumtypename是自定義的一種數(shù)據(jù)數(shù)據(jù)類型名,而enumvariablename為enumtypename類型的ー個變量,也就是我們平時常說的枚舉變量。實(shí)際上enum_type_name類型是対-個變量取值范圍的限定,而花括號內(nèi)是它的取值范圍,即enumtypename類型的變量enumvariablename只能取值為花括號內(nèi)的任何?個值,如果賦給該類型變量的值不在列表中,則會報錯或者警告。ENUM_CONST_1、ENUM_CONST_2 ENUM_CONST_n,這些成員都是常量,也就是我們平時所說的枚舉常量(常量一般用大寫)。enum變量類型還可以給其中的常量符號賦值,如果不賦值則會從被賦初值的那個常量開始依次加1,如果都沒有賦值,它們的值從0開始依次遞增1〇如分別用ー個常數(shù)表示不同顏色:enumColorGREEN=1,RED,BLUE,GREENRED=10,GREENBLUE}ColorVal;其中各常量名代表的數(shù)值分別為:GREEN=1RED=2BLUE=3GREEN_RED=10GREENBLUE=11枚舉與#define宏的區(qū)別卜.面再看看枚舉與#define宏的區(qū)別:1),2),3),A),B),#define宏常量是在預(yù)編譯階段進(jìn)行簡單替換。枚舉常量則是在編譯的時1),2),3),A),B),枚舉可以一次定義大量相關(guān)的常量,而#define宏一次只能定義一個。留兩個問題:枚舉能做到事,#define宏能不能都做到?如果能,那為什么還需要枚舉?sizeof(ColorVal)的值為多少?為什么?偉大的縫紉師?一typedef關(guān)鍵字在實(shí)際項(xiàng)目中,為了方便,可能很多數(shù)據(jù)類型(尤其是結(jié)構(gòu)體之類的自定義數(shù)據(jù)類型)需要我們重新取ー個適用實(shí)際情況的別名。這時候typedef就可以幫助我們。例如:typedefstructstudent//code}Stu_st,*Stu_pst;〃命名規(guī)則請參考本章前面部分A),structstudentB)A),structstudentB),structstudent*stu2I和Stu_pststu2:和Stu_st*stu2J沒有區(qū)別。這個地方很多初學(xué)者迷惑,B)的兩個定義為什么相等呢?其實(shí)很好理解。我們把“小可愛”。A_Ao好,下面再把typedefC),constStu_pstD),Stu_pstconst大多數(shù)初學(xué)者認(rèn)為〇astructstudent{/*code*/}n看成一個整體,typedef就是給ustructstudent{/*codc*/}>>取了個別名叫“Stust";同時給"structstudent{/*code*/}*"取了個別名叫"Stu_pst"。只不過這兩個名字同時取而已,好比你給你家小狗取了“小可愛”。A_Ao好,下面再把typedefC),constStu_pstD),Stu_pstconst大多數(shù)初學(xué)者認(rèn)為〇stu3;stu4;里const修飾的是stu3指向的對象;D)里const修飾的是stu4這個指針。很遺憾,〇里const修飾的并不是stu3指向的對象。那const這時候到底修飾的是什么呢?我們在講解constinti的時候說過const放在類型名“inビ前后都行;而constint*p與int*constp則完全不一樣。也就是說,我們看const修飾誰都時候完全可以將數(shù)據(jù)類型名視而不見,當(dāng)它不存在。反過來再看“constStu_pststu3",Stu_pst是“structstudent{/*code*/}的別名,“structstudent{/*code*/}*"是?個整體。對于編譯器來說,只認(rèn)為Stu_pst是ー個類型名,所以在解析的時候很自然的把“Stu_p短’這個數(shù)據(jù)類型名忽略掉?,F(xiàn)在知道const到底修飾的是什么了吧?A_Aotypedef與#define的區(qū)別噢,上帝!這真要命!別急,要命的還在后面呢??慈缦吕?E),#defineINT32intunsignedINT32i=10;F),typedefintint32;unsignedint32j=10;其中F)編譯出錯,為什么呢?E)不會出錯,這很好理解,因?yàn)樵陬A(yù)編譯的時候INT32被替換為int,而unsignedinti=10;語句是正確的。但是,很可惜,用typedef取的別名不支持這種類型擴(kuò)展。另外,想想typedefstaticintint32行不行?為什么?下面再看ー個與#define宏有關(guān)的例子:G),#definePCHARchar*PCHARp3,p4;H),typedefchar*pchar;pcharpl,p2;兩組代碼編譯都沒有問題,但是,這里的P4卻不是指針,僅僅是ー個char類型的字符。這種錯誤很容易被忽略,所以用#define的時候要慎之又慎。關(guān)于#define當(dāng)然還有很多話題需要討論,請看預(yù)處理第二章符號表(2.1)標(biāo)準(zhǔn)C語言的基本符號符號名稱符號名稱逗號 >右尖括號圓點(diǎn)!感嘆號;分號 |豎線冒號/斜杠問號、反斜杠單引號~波折號雙引號#井號(左圓括號)右圓括號f左方括號] 右方括號(左大括號} 右大括號%百分號&and(與)Axor(異或)?乘號-減號等于號<左尖括號+加號C語言的基本符號就有20多個,每個符號可能同時具有多重含義,而且這些符號之間相互組合又使得C語言中的符號變得更加復(fù)雜起來。注釋符號幾個似非而是的注釋問題C語言的注釋可以出現(xiàn)在C語言代碼的任何地方。這句話對不對?這是我當(dāng)學(xué)生時我老師問的ー個問題。我當(dāng)時回答是不對。好,那我們就看看下面的例子:A),int/*...*/i;B),char*s=Habcdefgh//hijklmn”;C),//Isita\validcomment?D),in/*...*/ti;我們知道C語言里可以有兩種注釋方式:/**/和//。那上面3條注釋對不對呢?建議你親自在編譯器中測試ー下。上述前3條注釋都是正確的,最后一條不正確。A),有人認(rèn)為編譯器剔除掉注釋后代碼會被解析成inti,所以不正確。編譯器的確會將注釋剔除,但不是簡單的剔除,而是用空格代替原來的注釋。B),我們知道雙引號引起來的都是字符串常量,那雙斜杠也不例外。C),這是一條合法的注釋,因?yàn)?、是ー個接續(xù)符。關(guān)于接續(xù)符D),前面說過注釋會被空格替換,那這條注釋不正確就很好理解了。但注意:/*…*/這種形式的注釋不能嵌套,如:/?這是/?非法的?/*/,因?yàn)??總是與離它最近的?/匹配。y=x/*p,這是表示x除以p指向的內(nèi)存里的值,把結(jié)果賦值為y?我們可以在編譯器上測試ー下,編譯器提示出錯。實(shí)際上,編譯器把/?當(dāng)作是一段注釋的開始,把/?后面的內(nèi)容都當(dāng)作注釋內(nèi)容,直到出現(xiàn)?/為止。這個表達(dá)式其實(shí)只是表示把x的值賦給y,/*后面的內(nèi)容都當(dāng)作注釋。但是,由于沒有找到*/,所以提示出錯。我們可以把上面的表達(dá)式修改一下:y=x/*p或者y=x/(*p)這樣的話,表達(dá)式的意思就是x除以p指向的內(nèi)存里的值,把結(jié)果賦值為y了。也就是說只要斜杠(/)和星號(*)之間沒有空格,都會被當(dāng)作注釋的開始。這一點(diǎn)一定要注意。2.1.3.3,出色注釋的基本要求【規(guī)則2-1I注釋應(yīng)當(dāng)準(zhǔn)確、易懂,防止有二義性。錯誤的注釋不但無益反而有害?!疽?guī)則2-2】邊寫代碼邊注釋,修改代碼同時修改相應(yīng)的注釋,以保證注釋與代碼的一致性。不再有用的注釋要及時刪除?!疽?guī)則2-3】注釋是對代碼的“提示”,而不是文檔。程序中的注釋應(yīng)當(dāng)簡単明了,注釋太多了會讓人眼花繚亂?!疽?guī)則2>4】一目了然的語句不加注釋。例如:i++;/*i加1*/多余的注釋【規(guī)則2-5]對于全局?jǐn)?shù)據(jù)(全局變量、常量定義等)必須要加注釋?!疽?guī)則2-6]注釋采用英文,盡量避免在注釋中使用縮寫,特別是不常用縮寫。因?yàn)椴灰欢ㄋ械木幾g器都能顯示中文,別人打開你的代碼,你的注釋也許是一團(tuán)亂碼。還有,你的代碼不一定是懂中文的人閱讀?!疽?guī)則2-7]注釋的位置應(yīng)與被描述的代碼相鄰,可以與語句在同一行,也可以在上行,但不可放在下方。同一結(jié)構(gòu)中不同域的注釋要對齊?!疽?guī)則2-8]當(dāng)代碼比較長,特別是有多重嵌套時,應(yīng)當(dāng)在ー些段落的結(jié)束處加注釋,便于閱讀?!疽?guī)則2-9]注釋的縮進(jìn)要與代碼的縮進(jìn)一致?!疽?guī)則2-10I注釋代碼段時應(yīng)注重“為何做(why)”,而不是“怎么做(how)”。說明怎么做的注釋ー般停留在編程語言的層次,面不是為了說明問題。盡力闡述“怎么做”的注釋一般沒有告訴我們操作的意圖,而指明“怎么做”的注釋通常是冗余的?!疽?guī)則2-11]數(shù)值的單位一定要注釋。注釋應(yīng)該說明某數(shù)值的單位到底是什么意思。比如:關(guān)于長度的必須說明單位是毫米,米,還是千米等:關(guān)于時間的必須說明單位是時,分,秒,還是毫秒等?!疽?guī)則2-12I對變量的范圍給出注釋?!疽?guī)則2-13]對ー系列的數(shù)字編號給出注釋,尤其在編寫底層驅(qū)動程序的時候(比如管腳編號)?!疽?guī)則2-13I對于函數(shù)的入口出口數(shù)據(jù)給出注釋。接續(xù)符和轉(zhuǎn)義符C語言里以反斜杠(ヽ)表示斷行。編譯器會將反斜杠剔除掉,跟在反斜杠后面的字符自動接續(xù)到前一行。但是注意:反斜杠之后不能有空格,反斜杠的下一行之前也不能有空格。當(dāng)然你可以測試一下加了空格之后的效果。反斜杠除了可以被用作接續(xù)符,還能被用作轉(zhuǎn)義字符的開始標(biāo)識。常用的轉(zhuǎn)義字符及其含義:轉(zhuǎn)義字符 轉(zhuǎn)義字符的意義\n回車換行\(zhòng)t橫向跳到下一制表位置\v豎向跳格\b退格\r回車\f走紙換頁\\反斜扛符"'"V單引號符\a鳴鈴\dddl-3位ハ進(jìn)制數(shù)所代表的字符\xhhl~2位十六進(jìn)制數(shù)所代表的字符廣義地講,C語言字符集中的任何ー個字符均可用轉(zhuǎn)義字符來表示。表中的、ddd和'xhh正是為此而提出的。ddd和hh分別為ハ進(jìn)制和十六進(jìn)制的ASCI!代碼。如'102表示字母"B",\134表示反斜線,'XOA表示換行等。單引號、雙引號我們知道雙引號引起來的都是字符串常量,單引號引起來的都是字符常量。位運(yùn)算符C語言中位運(yùn)算包括下面幾種:&按位與!按位或A按位異或?取反?左移?右移前4種操作很簡單,一般不會出錯。但要注意按位運(yùn)算符|和&與邏輯運(yùn)算符||和&&完全是兩碼事,別混淆了。其中按位異或操作可以實(shí)現(xiàn)不用第三個臨時變量交換兩個變量的值:aA=b;bA=a;aA=b;但并不推薦這么做,因?yàn)檫@樣的代碼讀起來很費(fèi)勁。左移和右移下面討論ー下左移和右移:左移運(yùn)算符“〈グ’是雙目運(yùn)算符。其功能把,?“左邊的運(yùn)算數(shù)的各二進(jìn)位全部左移若干位,由“<<”右邊的數(shù)指定移動的位數(shù),高位丟棄,低位補(bǔ)〇〇右移運(yùn)算符“>>”是雙目運(yùn)算符。其功能是把“>>"左邊的運(yùn)算數(shù)的各二進(jìn)位全部右移若干位,''>>”右邊的數(shù)指定移動的位數(shù)。但注意:對于有符號數(shù),在右移時,符號位將隨同移動。當(dāng)為正數(shù)時,最髙位補(bǔ)0:而為負(fù)數(shù)時,符號位為1,最高位是補(bǔ)0或是補(bǔ)1取決于編譯系統(tǒng)的規(guī)定。TurboC和很多系統(tǒng)規(guī)定為補(bǔ)100x01?2+30:或0x01?2-3;這樣行嗎?不行。ー個整型數(shù)長度為32位,左移32位發(fā)生了什么事情?溢出!左移ー1位呢?反過來移?所以,左移和右移的位數(shù)是有講究的。左移和右移的位數(shù)不能大于數(shù)據(jù)的長度,不能小于0。++、ー操作符這絕對是ー對讓人頭疼的兄弟。先來點(diǎn)簡單的:inti=3;(■H~i)+(++i)+(++i);表達(dá)式的值為多少?15嗎?16嗎?18嗎?其實(shí)對于這種情況,C語言標(biāo)準(zhǔn)并沒有作出規(guī)定。有點(diǎn)編譯器計算出來為18,因?yàn)閕經(jīng)過3次自加后變?yōu)?,然后3個6相加得18;而有的編譯器計算出來為16(比如VisualC++6.0),先計算前兩個i的和,這時候i自加兩次,2個i的和為10,然后再加上第三次自加的i得16。其實(shí)這些沒有必要辯論,用到哪個編譯器寫句代碼測試就行了。但不會計算出15的結(jié)果來的。++、一作為前綴,我們知道是先自加或自減,然后再做別的運(yùn)算;但是作為后綴時,到底什么時候自加、自減?這是很多初學(xué)者迷糊的地方。假設(shè)i=0.看例子:A)j=(i++,i++,i++);B),for(i=0;i<10;i++)(//code)C)>k=(i++)+ (i++)+(i++)5你可以試著計算他們的結(jié)果。A)例子為逗號表達(dá)式,i在遇到每個逗號后,認(rèn)為本計算單位已經(jīng)結(jié)束,i這時候自加。關(guān)于逗號表達(dá)式與“++”或“-”的連用,還有一個比較好的例子:intx;inti=3;x=(++i,i-H-,i+10);問X的值為多少?i的值為多少?按照上面的講解,可以很清楚的知道,逗號表達(dá)式中,i在遇到每個逗號后,認(rèn)為本計算單位已經(jīng)結(jié)束,i這時候自加。所以,本例子計算完后,i的值為5,x的值為15。B)例子i與10進(jìn)行比較之后,認(rèn)為本計算單位已經(jīng)結(jié)束,i這時候自加。C)例子i遇到分號オ認(rèn)為本計算單位已經(jīng)結(jié)束,i這時候自加。也就是說后綴運(yùn)算是在本計算單位計算結(jié)束之后再自加或自減。C語言里的計算単位大體分為以上3類。2/(-2)的值是多少?除法運(yùn)算在小學(xué)就掌握了的,這里還要討論什么呢?別急,先計算下面這個例子:2/(-2)的值為多少?2%(-2)的值呢?如果與你想象的結(jié)果不一致,不要驚訝。我們先看看下面這些規(guī)則:假定我們讓a除以b,商為q,余數(shù)為r:q=a/b;r=a%b;這里不妨先假定b大于〇。我們希望a、b、q、r之間維持什么樣的關(guān)系呢?1I最重要的一點(diǎn),我們希望q*b+r==a,因?yàn)檫@是定義余數(shù)的關(guān)系。2,如果我們改變a的正負(fù)號,我們希望q的符號也隨之改變,但q的絕對值不會變。3,當(dāng)b>0時,我們希望保證r>=0且r<bo這三條性質(zhì)是我們認(rèn)為整數(shù)除法和余數(shù)操作所應(yīng)該具備的。但是,很不幸,它們不可能同時成立。先考慮ー個簡單的例子:3/2,商為1,余數(shù)也為1〇此時,第一條性質(zhì)得到了滿足。好,把例子稍微改寫ー下:(-3)/2的值應(yīng)該是多少呢?如果要滿足第二條性質(zhì),答案應(yīng)該是ノ。但是,如果是這樣,余數(shù)就必定是」,這樣第三條性質(zhì)就無法滿足了。如果我們首先滿足第三條性質(zhì),即余數(shù)是1,這種情況下根據(jù)第一條性質(zhì),商應(yīng)該為ー2,那么第二條性質(zhì)又無法滿足了。上面的矛盾似乎無法解決。因此,C語言或者其他語言在實(shí)現(xiàn)整數(shù)除法截斷運(yùn)算時,必須放棄上述三條性質(zhì)中的至少一條。大多數(shù)編程語言選擇了放棄第三條,面改為要求余數(shù)與被除數(shù)的正負(fù)號相同。這樣性質(zhì)1和性質(zhì)2就可以得到滿足。大多數(shù)C語言編譯器也都是如此。但是,C語言的定義只保證了性質(zhì)1,以及當(dāng)a>=0且b>0時,保證M<|b|以及r>=0?后面部分的保證與性質(zhì)2或性質(zhì)3比較起來,限制性要弱得多。通過上面的解釋,你是否能準(zhǔn)確算出2/(-2)和2%(-2)的值呢?第三章預(yù)處理預(yù)處理名稱意義#define宏定義#undef撤銷已定義過的宏名#include使編譯程序?qū)⒘硪辉次募度氲綆в?include的源文件中#if 的一般含義是如果#if后面的常量表達(dá)式為true,則編譯它與#endif間的代碼,否則跳過這些代碼。命令#endif標(biāo)識」?個#if塊的結(jié)束。#else#else 命令的功能有點(diǎn)象C語言中的else,#else建立另ー選擇(在#if失#elif敗的情況下)。#elif命令意義與elseif相同,它形成一個ifelse-if階#endif 梯狀語句,可進(jìn)行多種編譯選擇。#ifdef用#iftief與#ifhdef命令分別表示“如果有定義”及“如果無定義”,是條#ifhdef 件編譯的另ー種方法。#line改變當(dāng)前行數(shù)和文件名稱,它們是在編譯程序中預(yù)先定義的標(biāo)識符命令的基本形式如下:#linenumber["filename"]#error編譯程序時,只要遇到#error就會生成一個編譯錯誤提示消息,并停止編譯#pragma為實(shí)現(xiàn)時定義的命令,它允許向編譯程序傳送各種指令例如,編譯程序可能有一種選擇,它支持對程序執(zhí)行的跟蹤??捎?pragma語句指定一個跟蹤選擇。另外ANSI標(biāo)準(zhǔn)C還定義了如下幾個宏:_LINE_表示正在編譯的文件的行號_FILE_表示正在編譯的文件的名字_DATE_表示編譯時刻的日期字符串,例如:"25Dec2007"_TIME_表示編譯時刻的時間字符串,例如:"12:30:55"_STDC_判斷該文件是不是定義成標(biāo)準(zhǔn)C程序如果編譯器不是標(biāo)準(zhǔn)的,則可能僅支持以上宏的一部分,或根本不支持。當(dāng)然編譯器也有可能還提供其它預(yù)定義的宏名。注意:宏名的書寫由標(biāo)識符與兩邊各二條下劃線構(gòu)成。,宏定義數(shù)值宏常量#define宏定義,它可以出現(xiàn)在代碼的任何地方,從本行宏定義開始,以后的代碼就就都認(rèn)識這個宏了:也可以把任何東西定義成宏。因?yàn)榫幾g器會在預(yù)編譯的時候用真身替換替身,而在我們的代碼里面卻又用常常用替身來幫忙。#defineERRORPOWEROFF-1如果你在代碼里不用ERROR_POWEROFF這個宏而用ー1,尤其在函數(shù)返回錯誤代碼的時候(往往一個開發(fā)ー個系統(tǒng)需要定義很多錯誤代碼)??吓律系鄱紵o法知道一1表示的是什么意思吧。這個-1,我們一般稱為“魔鬼數(shù)”,上帝遇到它也會發(fā)狂的。所以,我奉勸你代碼里一定不要出現(xiàn)“魔鬼數(shù)”。第一章我們詳細(xì)討論了const這個關(guān)鍵字,我們知道const修飾的數(shù)據(jù)是有類型的,而define宏定義的數(shù)據(jù)沒有類型。為了安全,我建議你以后在定義一些宏常數(shù)的時候用const代替,編譯器會給const修飾的只讀變量做類型校驗(yàn),減少錯誤的可能。但一定要注意const修飾的不是常量而是readonly的變量,const修飾的只讀變量不能用來作為定義數(shù)組的維數(shù),也不能放在case關(guān)鍵字后面。字符串宏常量除了定義宏常數(shù)之外,經(jīng)常還用來定義字符串,尤其是路徑:A),#defineENG_PATH_1E:\English\listen_to_this\listen_to_this_3B),#defineENG_PATH_2"E:\English\listen_to_this\listen_to_this_3”噢,到底哪ー個正確呢?如果路徑太長,一行寫下來比較別扭怎么辦?用反斜杠接續(xù)符?。篊),#defineENG_PATH_3E:\English\listen_to_this\listen\_to_this_3還沒發(fā)現(xiàn)問題?這里用了4個反斜杠,到底哪個是接續(xù)符?回去看看接續(xù)符反斜杠。反斜杠作為接續(xù)符時,在本行其后面不能再有任何字符,空格都不行。所以,只有最后ー個反斜杠オ是接續(xù)符。至于A)和B),那要看你怎么用了,既然define宏只是簡單的替換,那給ENG_PATH_1加上雙引號不就成了:“ENG_PATH_1”。但是請注意:有的系統(tǒng)里規(guī)定路徑的要用雙反斜杠“\\”,比如:#defineENG_PATH_4E:\\English\\listen_to_this\\listen_to_this_3用define宏定義注釋符號?上面對define的使用都很簡單,再看看下面的例子:#defineBSC//#defineBMC/*#defineEMC*/D),BSCmysingle-linecommentE),BMCmymulti-linecommentEMCD)和E)都錯誤,

溫馨提示

  • 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)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論