對(duì)C語(yǔ)言編程標(biāo)準(zhǔn)以及聲明的基本理解
c語(yǔ)言標(biāo)準(zhǔn)
1978年,丹尼斯·里奇(Dennis Ritchie)和Brian Kernighan合作出版了《C程序設(shè)計(jì)語(yǔ)言》的第一版。書中介紹的C語(yǔ)言標(biāo)準(zhǔn)也被C語(yǔ)言程序設(shè)計(jì)師稱作“K&R C”,第二版的書中也包含了一些ANSI C的標(biāo)準(zhǔn)。K&R C主要介紹了以下特色:
結(jié)構(gòu)(struct)類型
長(zhǎng)整數(shù)(long int)類型
無(wú)符號(hào)整數(shù)(unsigned int)類型
把運(yùn)算符=+和=-改為+=和-=。因?yàn)?+和=-會(huì)使得編譯器不知道用戶要處理i = +10還是i =- 10,使得處理上產(chǎn)生混淆。
即使在后來(lái)ANSI C標(biāo)準(zhǔn)被提出的許多年后,K&R C仍然是許多編譯器的最低標(biāo)準(zhǔn)要求,許多老舊的編譯仍然運(yùn)行K&R C的標(biāo)準(zhǔn)。
C89
1989年,C語(yǔ)言被 ANSI 標(biāo)準(zhǔn)化(ANSI X3.159-1989)。標(biāo)準(zhǔn)化的一個(gè)目的是擴(kuò)展K&R C。這個(gè)標(biāo)準(zhǔn)包括了一些新特性。在K&R出版后,一些新特性被非官方地加到C語(yǔ)言中。
void 函數(shù)
函數(shù)返回 struct 或 union 類型
void * 數(shù)據(jù)類型
在 ANSI標(biāo)準(zhǔn)化自己的過(guò)程中,一些新的特性被加了進(jìn)去。ANSI也規(guī)定一套了標(biāo)準(zhǔn)函數(shù)庫(kù)。ANSI ISO(國(guó)際標(biāo)準(zhǔn)化組織)成立 ISO/IEC JTC1/SC22/WG14 工作組,來(lái)規(guī)定國(guó)際標(biāo)準(zhǔn)的C語(yǔ)言。通過(guò)對(duì)ANSI標(biāo)準(zhǔn)的少量修改,最終通過(guò)了 ISO 9899:1990。隨后,ISO標(biāo)準(zhǔn)被 ANSI 采納。
傳統(tǒng)C語(yǔ)言到ANSI/ISO標(biāo)準(zhǔn)C語(yǔ)言的改進(jìn)包括:
增加了真正的標(biāo)準(zhǔn)庫(kù)
新的預(yù)處理命令與特性
函數(shù)原型允許在函數(shù)申明中指定參數(shù)類型
一些新的關(guān)鍵字,包括 const、volatile 與 signed
寬字符、寬字符串與字節(jié)多字符
對(duì)約定規(guī)則、聲明和類型檢查的許多小改動(dòng)與澄清
WG14工作小組之后又于1995年,對(duì)1985年頒布的標(biāo)準(zhǔn)做了兩處技術(shù)修訂(缺陷修復(fù))和一個(gè)補(bǔ)充(擴(kuò)展)。下面是 1995 年做出的所有修改:
3 個(gè)新的標(biāo)準(zhǔn)庫(kù)頭文件 iso646.h、wctype.h 和 wchar.h
幾個(gè)新的記號(hào)與預(yù)定義宏,用于對(duì)國(guó)際化提供更好的支持
printf/sprintf 函數(shù)一系列新的格式代碼
大量的函數(shù)和一些類型與常量,用于多字節(jié)字符和寬字節(jié)字符
C99
在 ANSI的標(biāo)準(zhǔn)確立后,C語(yǔ)言的規(guī)范在一段時(shí)間內(nèi)沒(méi)有大的變動(dòng),然而C++在自己的標(biāo)準(zhǔn)化建立過(guò)程中繼續(xù)發(fā)展壯大。《標(biāo)準(zhǔn)修正案一》在1995年為C語(yǔ)言 建立了一個(gè)新標(biāo)準(zhǔn),但是只修正了一些C89標(biāo)準(zhǔn)中的細(xì)節(jié)和增加更多更廣得國(guó)際字符集支持。不過(guò),這個(gè)標(biāo)準(zhǔn)引出了1999年ISO 9899:1999的發(fā)表。它通常被成為C99。C99被ANSI于2000年3月采用。
在C99中包括的特性有:
對(duì)編譯器限制增加了,比如源程序每行要求至少支持到 4095 字節(jié),變量名函數(shù)名的要求支持到 63 字節(jié)(extern 要求支持到 31)
預(yù)處理增強(qiáng)了。例如:
宏支持取可變參數(shù) #define Macro(...) __VA_ARGS__
使用宏的時(shí)候,參數(shù)如果不寫,宏里用 #,## 這樣的東西會(huì)擴(kuò)展成空串。(以前會(huì)出錯(cuò)的)
支持 // 行注釋(這個(gè)特性實(shí)際上在C89的很多編譯器上已經(jīng)被支持了)
增加了新關(guān)鍵字 restrict, inline, _Complex, _Imaginary, _Bool
支持 long long, long double _Complex, float _Complex 這樣的類型
支持 <: :> <% %> %: %:%: ,等等奇怪的符號(hào)替代,D&E 里提過(guò)這個(gè)
支持了不定長(zhǎng)的數(shù)組。數(shù)組的長(zhǎng)度就可以用變量了。聲明類型的時(shí)候呢,就用 int a[*] 這樣的寫法。不過(guò)考慮到效率和實(shí)現(xiàn),這玩意并不是一個(gè)新類型。所以就不能用在全局里,或者 struct union 里面,如果你用了這樣的東西,goto 語(yǔ)句就受限制了。
變量聲明不必放在語(yǔ)句塊的開頭,for 語(yǔ)句提倡這么寫 for(int i=0;i<100;++i) 就是說(shuō),int i 的聲明放在里面,i 只在 for 里面有效。
當(dāng)一個(gè)類似結(jié)構(gòu)的東西需要臨時(shí)構(gòu)造的時(shí)候,可以用(type_name){xx,xx,xx} 這有點(diǎn)像 C++ 的構(gòu)造函數(shù)
初始化結(jié)構(gòu)的時(shí)候現(xiàn)在可以這樣寫:
struct {int a[3],b;} hehe[] = { [0].a = {1}, [1].a = 2 };
struct {int a, b, c, d;} hehe = { .a = 1, .c = 3, 4, .b = 5} // 3,4 是對(duì) .c,.d 賦值的
字符串里面,/u 支持 unicode 的字符
支持 16 進(jìn)制的浮點(diǎn)數(shù)的描述
所以 printf scanf 的格式化串多支持了 ll / LL(VC6 里用的 I64)對(duì)應(yīng)新的 long long 類型。
浮點(diǎn)數(shù)的內(nèi)部數(shù)據(jù)描述支持了新標(biāo)準(zhǔn),這個(gè)可以用 #pragma 編譯器指定
除了已經(jīng)有的 __line__ __file__ 以外,又支持了一個(gè) __func__ 可以得到當(dāng)前的函數(shù)名
對(duì)于非常數(shù)的表達(dá)式,也允許編譯器做化簡(jiǎn)
修改了對(duì)于/% 處理負(fù)數(shù)上的定義,比如老的標(biāo)準(zhǔn)里 -22 / 7 = -3, -22 % 7 = -1 而現(xiàn)在 -22 / 7 = -4, -22 % 7 = 6
取消了不寫函數(shù)返回類型默認(rèn)就是 int 的規(guī)定
允許 struct 定義的最后一個(gè)數(shù)組寫做 [] 不指定其長(zhǎng)度描述
const const int i;將被當(dāng)作 const int i;處理
增 加和修改了一些標(biāo)準(zhǔn)頭文件,比如定義 bool 的 <stdbool.h> 定義一些標(biāo)準(zhǔn)長(zhǎng)度的 int 的 <inttypes.h> 定義復(fù)數(shù)的 <complex.h> 定義寬字符的 <wctype.h> 有點(diǎn)泛型味道的數(shù)學(xué)函數(shù) <tgmath.h> 跟浮點(diǎn)數(shù)有關(guān)的 <fenv.h>。<stdarg.h> 里多了一個(gè) va_copy 可以復(fù)制 ... 的參數(shù)。<time.h> 里多了個(gè) struct tmx 對(duì) struct tm 做了擴(kuò)展
輸入輸出對(duì)寬字符還有長(zhǎng)整數(shù)等做了相應(yīng)的支持
相對(duì)于c89的變化還有
1、增加restrict指針
C99中增加了公適用于指針的restrict類型修飾符,它是初始訪問(wèn)指針?biāo)笇?duì)象的惟一途徑,因此只有借助restrict指針表達(dá)式才能 訪問(wèn)對(duì)象。restrict指針指針主要用做函數(shù)變?cè)蛘咧赶蛴蒻alloc()函數(shù)所分配的內(nèi)存變量。restrict數(shù)據(jù)類型不改變程序的語(yǔ)義。
如果某個(gè)函數(shù)定義了兩個(gè)restrict指針變?cè)幾g程序就假定它們指向兩個(gè)不同的對(duì)象,memcpy()函數(shù)就是restrict指針的一個(gè)典型應(yīng)用示例。C89中memcpy()函數(shù)原型如下:
代碼: void *memcpy (void *s1, const void *s2, size_t size);
如果s1和s2所指向的對(duì)象重疊,其操作就是未定義的。memcpy()函數(shù)只能用于不重疊的對(duì)象。C99中memcpy()函數(shù)原型如下:代 碼: void *memcpy(void *restrict s1, const void *restrict s2,size_t size);
通過(guò)使用restrict修飾s1和s2 變?cè)?,可確保它們?cè)谠撛椭兄赶虿煌膶?duì)象。
2、inline(內(nèi)聯(lián))關(guān)鍵字
內(nèi)聯(lián)函數(shù)除了保持結(jié)構(gòu)化和函數(shù)式的定義方式外,還能使程序員寫出高效率的代碼。函數(shù)的每次調(diào)用與返回都會(huì)消耗相當(dāng)大的系統(tǒng)資源,尤其是當(dāng)函數(shù)調(diào) 用發(fā)生在重復(fù)次數(shù)很多的循環(huán)語(yǔ)句中時(shí)。一般情況下,當(dāng)發(fā)生一次函數(shù)調(diào)用時(shí),變?cè)枰M(jìn)棧,各種寄存器內(nèi)存需要保存。當(dāng)函數(shù)返回時(shí),寄存器的內(nèi)容需要恢復(fù)。 如果該函數(shù)在代碼內(nèi)進(jìn)行聯(lián)機(jī)擴(kuò)展,當(dāng)代碼執(zhí)行時(shí),這些保存和恢復(fù)操作旅游活動(dòng)會(huì)再發(fā)生,而且函數(shù)調(diào)用的執(zhí)行速度也會(huì)大大加快。函數(shù)的聯(lián)機(jī)擴(kuò)展會(huì)產(chǎn)生較長(zhǎng)的 代碼,所以只應(yīng)該內(nèi)聯(lián)對(duì)應(yīng)用程序性能有顯著影響的函數(shù)以及長(zhǎng)度較短的函數(shù)。
3、新增數(shù)據(jù)類型
_Bool
值是0或1。C99中增加了用來(lái)定義bool、true以及false宏的頭文件夾<stdbool.h>,以便程序員能夠編寫同時(shí)兼容于C與C++的應(yīng)用程序。在編寫新的應(yīng)用程序時(shí),應(yīng)該使用
<stdbool.h>頭文件中的bool宏。
_Complex and _Imaginary
C99標(biāo)準(zhǔn)中定義的復(fù)數(shù)類型如下:float_Complex;float_Imaginary;double_Complex;double_Imaginary;long double_Complex;long double_Imaginary。
<complex.h>頭文件中定義了complex和imaginary宏,并將它們擴(kuò)展為_Complex和 _Imaginary,因此在編寫新的應(yīng)用程序時(shí),應(yīng)該使用<stdbool.h>頭文件中的complex和imaginary宏。
long long int
C99標(biāo)準(zhǔn)中引進(jìn)了long long int(-(2e63 - 1)至2e63 - 1)和unsigned long long int(0 - 2e64 - 1)。long long int能夠支持的整數(shù)長(zhǎng)度為64位。
4、對(duì)數(shù)組的增強(qiáng)
可變長(zhǎng)數(shù)組
C99中,程序員聲明數(shù)組時(shí),數(shù)組的維數(shù)可以由任一有效的整型表達(dá)式確定,包括只在運(yùn)行時(shí)才能確定其值的表達(dá)式,這類數(shù)組就叫做可變長(zhǎng)數(shù)組,但是只有局部數(shù)組才可以是變長(zhǎng)的。
可變長(zhǎng)數(shù)組的維數(shù)在數(shù)組生存期內(nèi)是不變的,也就是說(shuō),可變長(zhǎng)數(shù)組不是動(dòng)態(tài)的??梢宰兓闹皇菙?shù)組的大小。可以使用*來(lái)定義不確定長(zhǎng)的可變長(zhǎng)數(shù)組。
數(shù)組聲明中的類型修飾符
在C99中,如果需要使用數(shù)組作為函數(shù)變?cè)?,可以在?shù)組聲明的方括號(hào)內(nèi)使用static關(guān)鍵字,這相當(dāng)于告訴編譯程序,變?cè)赶虻臄?shù)組將至少 包含指定的元素個(gè)數(shù)。也可以在數(shù)組聲明的方括號(hào)內(nèi)使用restrict,volatile,const關(guān)鍵字,但只用于函數(shù)變?cè)H绻褂?restrict,指針是初始訪問(wèn)該對(duì)象的惟一途徑。如果使用const,指針始終指向同一個(gè)數(shù)組。使用volatile沒(méi)有任何意義。
5、單行注釋
引入了單行注釋標(biāo)記 "http://" , 可以像C++一樣使用這種注釋了。
6、分散代碼與聲明
7、預(yù)處理程序的修改
a、變?cè)斜?/p>
宏可以帶變?cè)?,在宏定義中用省略號(hào)(...)表示。內(nèi)部預(yù)處理標(biāo)識(shí)符__VA_ARGS__決定變?cè)獙⒃诤翁幍玫教鎿Q。例:#define MySum(...) sum(__VA_ARGS__) 語(yǔ)句MySum(k,m,n);
將被轉(zhuǎn)換成:sum(k, m, n); 變?cè)€可以包含變?cè)?。例?#define compare(compf, ...) compf(__VA_ARGS__) 其中的compare(strcmp,"small", "large"); 將替換成:strcmp("small","large");
b、_Pragma運(yùn)算符
C99引入了在程序中定義編譯指令的另外一種方法:_Pragma運(yùn)算符。格式如下:
_Pragma("directive")
其中directive是要滿打滿算的編譯指令。_Pragma運(yùn)算符允許編譯指令參與宏替換。
c、內(nèi)部編譯指令
STDCFP_CONTRACT ON/OFF/DEFAULT 若為ON,浮點(diǎn)表達(dá)式被當(dāng)做基于硬件方式處理的獨(dú)立單元。默認(rèn)值是定義的工具。
STDCFEVN_ACCESS ON/OFF/DEFAULT 告訴編譯程序可以訪問(wèn)浮點(diǎn)環(huán)境。默認(rèn)值是定義的工具。
STDC CX_LIMITED_RANGE ON/OFF/DEFAULT 若值為ON,相當(dāng)于告訴編譯程序某程序某些含有復(fù)數(shù)的公式是可靠的。默認(rèn)是OFF。
d、新增的內(nèi)部宏
__STDC_HOSTED__ 若操作系統(tǒng)存在,則為1
__STDC_VERSION__ 199991L或更高。代表C的版本
__STDC_IEC_599__ 若支持IEC 60559浮點(diǎn)運(yùn)算,則為1
__STDC_IEC_599_COMPLEX__ 若支持IEC 60599復(fù)數(shù)運(yùn)算,則為1
__STDC_ISO_10646__ 由編譯程序支持,用于說(shuō)明ISO/IEC 10646標(biāo)準(zhǔn)的年和月格式:yyymmmL
9、復(fù)合賦值
C99中,復(fù)合賦值中,可以指定對(duì)象類型的數(shù)組、結(jié)構(gòu)或聯(lián)合表達(dá)式。當(dāng)使用復(fù)合賦值時(shí),應(yīng)在括弧內(nèi)指定類型,后跟由花括號(hào)圍起來(lái)的初始化列表;若類型為數(shù)組,則不能指定數(shù)組的大小。建成的對(duì)象是未命名的。
例: double *fp = (double[]) {1.1, 2.2, 3.3};
該語(yǔ)句用于建立一個(gè)指向double的指針fp,且該指針指向這個(gè)3元素?cái)?shù)組的第一個(gè)元素。 在文件域內(nèi)建立的復(fù)合賦值只在程序的整個(gè)生存期內(nèi)有效。在模塊內(nèi)建立的復(fù)合賦值是局部對(duì)象,在退出模塊后不再存在。
10、柔性數(shù)組結(jié)構(gòu)成員
C99中,結(jié)構(gòu)中的最后一個(gè)元素允許是未知大小的數(shù)組,這就叫做柔性數(shù)組成員,但結(jié)構(gòu)中的柔性數(shù)組成員前面必須至少一個(gè)其他成員。柔性數(shù)組成員 允許結(jié)構(gòu)中包含一個(gè)大小可變的數(shù)組。sizeof返回的這種結(jié)構(gòu)大小不包括柔性數(shù)組的內(nèi)存。包含柔性數(shù)組成員的結(jié)構(gòu)用malloc()函數(shù)進(jìn)行內(nèi)存的動(dòng)態(tài) 分配,并且分配的內(nèi)存應(yīng)該大于結(jié)構(gòu)的大小,以適應(yīng)柔性數(shù)組的預(yù)期大小。
11、指定的初始化符
C99中,該特性對(duì)經(jīng)常使用稀疏數(shù)組的程序員十分有用。指定的初始化符通常有兩種用法:用于數(shù)組,以及用于結(jié)構(gòu)和聯(lián)合。用于數(shù)組的格式: = vol; 其中,index表示數(shù)組的下標(biāo),vol表示本數(shù)組元素的初始化值。
例如: int x[10] = {[0] = 10, [5] = 30}; 其中只有x[0]和x[5]得到了初始化。用于結(jié)構(gòu)或聯(lián)合的格式如下:
member-name(成員名稱)
對(duì)結(jié)構(gòu)進(jìn)行指定的初始化時(shí),允許采用簡(jiǎn)單的方法對(duì)結(jié)構(gòu)中的指定成員進(jìn)行初始化。
例如: struct example{ int k, m, n; } object = {m = 10,n = 200};
其中,沒(méi)有初始化k。對(duì)結(jié)構(gòu)成員進(jìn)行初始化的順序沒(méi)有限制。
12、printf()和scanf()函數(shù)系列的增強(qiáng)
C99中printf()和scanf()函數(shù)系列引進(jìn)了處理long long int和unsigned long long int數(shù)據(jù)類型的特性。long long int 類型的格式修飾符是ll。在printf()和scanf()函數(shù)中,ll適用于d,i,o,u和x格式說(shuō)明符。另外,C99還引進(jìn)了hh修飾符。當(dāng)使用 d,i,o,u和x格式說(shuō)明符時(shí),hh用于指定char型變?cè)?。ll和hh修飾符均可以用于n說(shuō)明符。
格式修飾符a和A用在printf()函數(shù)中時(shí),結(jié)果將會(huì)輸出十六進(jìn)制的浮點(diǎn)數(shù)。格式如下:[-]0xh, hhhhp + d 使用A格式修飾符時(shí),x和p必須是大寫。A和a格式修飾符也可以用在scanf()函數(shù)中,用于讀取浮點(diǎn)數(shù)。調(diào)用printf()函數(shù)時(shí),允許在%f說(shuō)明 符前加上l修飾符,即%lf,但不起作用。
13、C99新增的庫(kù)
C89中標(biāo)準(zhǔn)的頭文件
<assert.h> 定義宏assert()
<ctype.h> 字符處理
<errno.h> 錯(cuò)誤報(bào)告
<float.h> 定義與實(shí)現(xiàn)相關(guān)的浮點(diǎn)值
<limits.h> 定義與實(shí)現(xiàn)相關(guān)的各種極限值
<locale.h> 支持函數(shù)setlocale()
<math.h> 數(shù)學(xué)函數(shù)庫(kù)使用的各種定義
<setjmp.h> 支持非局部跳轉(zhuǎn)
<signal.h> 定義信號(hào)值
<stdarg.h> 支持可變長(zhǎng)度的變?cè)斜?/p>
<stddef.h> 定義常用常數(shù)
<stdio.h> 支持文件輸入和輸出
<stdlib.h> 其他各種聲明
<string.h> 支持串函數(shù)
<time.h> 支持系統(tǒng)時(shí)間函數(shù)
C99新增的頭文件和庫(kù)
<complex.h> 支持復(fù)數(shù)算法
<fenv.h> 給出對(duì)浮點(diǎn)狀態(tài)標(biāo)記和浮點(diǎn)環(huán)境的其他方面的訪問(wèn)
<inttypes.h> 定義標(biāo)準(zhǔn)的、可移植的整型類型集合。也支持處理最大寬度整數(shù)的函數(shù)
<iso646.h> 首先在此1995年第一次修訂時(shí)引進(jìn),用于定義對(duì)應(yīng)各種運(yùn)算符的宏
<stdbool.h> 支持布爾數(shù)據(jù)類型類型。定義宏bool,以便兼容于C++
<stdint.h> 定義標(biāo)準(zhǔn)的、可移植的整型類型集合。該文件包含在<inttypes.h>中
<tgmath.h> 定義一般類型的浮點(diǎn)宏
<wchar.h> 首先在1995年第一次修訂時(shí)引進(jìn),用于支持多字節(jié)和寬字節(jié)函數(shù)
<wctype.h> 首先在1995年第一次修訂時(shí)引進(jìn),用于支持多字節(jié)和寬字節(jié)分類函數(shù)
14、__func__預(yù)定義標(biāo)識(shí)符
用于指出__func__所存放的函數(shù)名,類似于字符串賦值。
15、其它特性的改動(dòng)
放寬的轉(zhuǎn)換限制

不再支持隱含式的int規(guī)則
刪除了隱含式函數(shù)聲明
對(duì)返回值的約束
C99中,非空類型函數(shù)必須使用帶返回值的return語(yǔ)句。
擴(kuò)展的整數(shù)類型

對(duì)整數(shù)類型提升規(guī)則的改進(jìn)
C89中,表達(dá)式中類型為char,short int或int的值可以提升為int或unsigned int類型。
C99中,每種整數(shù)類型都有一個(gè)級(jí)別。例如:long long int 的級(jí)別高于int,int的級(jí)別高于char等。在表達(dá)式中,其級(jí)別低于int或unsigned int的任何整數(shù)類型均可被替換成int或unsigned int類型。
但是各個(gè)公司對(duì)C99的支持所表現(xiàn)出來(lái)的興趣不同。當(dāng)GCC和其它一些商業(yè)編譯器支持C99的大部分特性的時(shí)候,微軟和Borland卻似乎對(duì)此不感興趣。
GCC 支持C99,通過(guò) --std = c99命令行參數(shù)開啟。 例如:gcc --std = c99 test.c。默認(rèn)情況下GCC是用的GNU89標(biāo)準(zhǔn)
C語(yǔ)言聲明
優(yōu)先級(jí)規(guī)則分析
A.聲明從他的第一個(gè)標(biāo)識(shí)符(名字)開始讀取,然后按照優(yōu)先級(jí)順序依次讀取:
B 優(yōu)先級(jí)從高到低依次是:
B.1聲明中被括號(hào)括起來(lái)的那部分
B.2后綴操作符:
括號(hào)()表示這是一個(gè)函數(shù),而方括號(hào)[]表示這是一個(gè)數(shù)組。
B.3前綴操作符:星號(hào)*表示“指向...的指針”
C 如果const和(或)volatile關(guān)鍵字的后面緊跟類型說(shuō)明符(如int,long等),那么它用做子類型說(shuō)明符。在其他情況下, const和(或)volatile關(guān)鍵字作用于它左邊的臨近的指針星號(hào)。
例:
char * const *(*next)();
A 首先,看變量名(標(biāo)識(shí)符)“next”,并注意到它直接被括號(hào)所括住
B.1 所以先把括號(hào)里的東西作為一個(gè)整體,得出“next是一個(gè)指向...的指針”
B 然后考慮括號(hào)外面的東西,在星號(hào)前綴和括號(hào)后綴之間作出選擇
B.2 B.2規(guī)則告訴我們優(yōu)先級(jí)較高的是右邊的函數(shù)括號(hào),所以得出“next是一個(gè)函數(shù)指針,指向一個(gè)返回...的函數(shù)”
B.3 然后,處理前綴“*”,得出指針?biāo)傅膬?nèi)容
C 最后,把“char * const”解釋為指向字符的常量指針
更直觀一點(diǎn)可以看下圖

所以這個(gè)聲明表示“next”是一個(gè)指針,它指向一個(gè)函數(shù),該函數(shù)返回另一個(gè)指針,該指針指向一個(gè)類型為char的常量指針。
例子2 char *(* c[10]) (int **p)

那么合起來(lái)就是c是一個(gè)函數(shù)指針數(shù)組,他的返回類型是char *,參數(shù)是int **p
以下是來(lái)自c專家編程的一個(gè)分析聲明的程序
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#define MAXTOKENS 100
#define MAXTOKENLEN 64
enum type_tag { IDENTIFIER, QUALIFIER, TYPE};
struct token{
char type;
char string[MAXTOKENLEN];
};
int top = -1;
struct token stack[MAXTOKENS];
struct token this;
#define pop stack[top--]
#define push(s) stack[++top] = s
enum type_tag classify_string(void)
{
char *s = this.string;
if ( !strcmp(s,"const"))
{
strcpy(s,"read-only");
return QUALIFIER;
}
if (!strcmp(s,"volatile"))
return QUALIFIER;
if (!strcmp(s,"void"))
return TYPE;
if (!strcmp(s,"char"))
return TYPE;
if (!strcmp(s,"signed"))
return TYPE;
if (!strcmp(s,"unsigned"))
return TYPE;
if (!strcmp(s,"short"))
return TYPE;
if (!strcmp(s,"int"))
return TYPE;
if (!strcmp(s,"void"))
return TYPE;
if (!strcmp(s,"long"))
return TYPE;
if (!strcmp(s,"float"))
return TYPE;
if (!strcmp(s,"double"))
return TYPE;
if (!strcmp(s,"struct"))
return TYPE;
if (!strcmp(s,"union"))
return TYPE;
if (!strcmp(s,"enum"))
return TYPE;
return IDENTIFIER;
}
void gettoken(void)
{
char *p = this.string;
while((*p = getchar() ) == ' ');
if ( isalnum(*p) )
{
while( isalnum( *++p = getchar() ));
ungetc(*p , stdin);
*p = '/0';
this.type = classify_string();
return;
}
if (*p == '*' )
{
strcpy(this.string, "pointer to");
this.type = '*';
return;
}
this.string[1] = '/0';
this.type = *p;
return;
}
read_to_first_identifer()
{
gettoken();
while(this.type != IDENTIFIER )
{
push( this );
gettoken();
}
printf("%s is ",this.string);
gettoken();
}
deal_with_arrays()
{
while(this.type = '[' )
{
printf("array");
gettoken();
if ( isdigit(this.string[0]) )
{
printf("0..%d ",atoi(this.string)-1);
gettoken();
}
gettoken();
printf("of ");
}
}
deal_with_function_args()
{
while( this.type != ')' )
{
gettoken();
}
gettoken();
printf("function returning ");
}
deal_with_pointers()
{
while(stack[top].type == '*' )
{
printf("%s ", pop.string);
}
}
deal_with_declarator()
{
switch(this.type)
{
case '[' :deal_with_arrays();break;
case '(' :deal_with_function_args();
}
deal_with_pointers();
while( top >= 0 )
{
if ( stack[top].type == '(' )
{
pop;
gettoken();
deal_with_declarator();
}
else
printf("%s ",pop.string);
}
}
main()
{
read_to_first_identifer();
deal_with_declarator();
printf("/n");
return 0;
}
相關(guān)文章
C++ 詳解數(shù)據(jù)結(jié)構(gòu)中的搜索二叉樹
搜索二叉樹是一種具有良好排序和查找性能的二叉樹數(shù)據(jù)結(jié)構(gòu),包括多種操作,本篇只介紹插入,排序(遍歷),和刪除操作,重點(diǎn)是刪除操作比較復(fù)雜2022-04-04
C++11中跳轉(zhuǎn)initializer_list實(shí)現(xiàn)分析
這篇文章主要介紹了C++11中跳轉(zhuǎn)initializer_list實(shí)現(xiàn)分析,實(shí)例分析initializer_list<T>初體驗(yàn),結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04
C語(yǔ)言實(shí)現(xiàn)歌手比賽系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)歌手比賽系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05
C++數(shù)據(jù)結(jié)構(gòu)之實(shí)現(xiàn)鄰接表與鄰接矩陣的相互轉(zhuǎn)換
這篇文章主要為大家學(xué)習(xí)介紹了C++如何實(shí)現(xiàn)鄰接表與鄰接矩陣的相互轉(zhuǎn)換,文中的示例代碼簡(jiǎn)潔易懂,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-07-07
利用C++實(shí)現(xiàn)從std::string類型到bool型的轉(zhuǎn)換
利用C++實(shí)現(xiàn)從std::string類型到bool型的轉(zhuǎn)換。需要的朋友可以過(guò)來(lái)參考下。希望對(duì)大家有所幫助2013-10-10
C++詳解默認(rèn)參數(shù)的構(gòu)造函數(shù)及簡(jiǎn)單實(shí)例代碼
這篇文章主要介紹了 C++詳解默認(rèn)參數(shù)的構(gòu)造函數(shù)及簡(jiǎn)單實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2017-02-02

