前些天在看getopt源碼, 一種前所未見的函數定義方法
1 int 2 getopt(nargc, nargv, ostr) 3 int nargc; 4 char * const nargv[]; 5 const char *ostr; 6 { 7 static char *__progname = 0; 8 static char *place = EMSG; /* option letter processing */ 9 char *oli; /* option letter list index */ 10 __progname = __progname?__progname:_progname(*nargv); 11 12 _DIAGASSERT(nargv != NULL); 13 _DIAGASSERT(ostr != NULL); 14 15 if (optreset || !*place) { /* update scanning pointer */ 16 optreset = 0; 17 if (optind >= nargc || *(place = nargv[optind]) != '-') { 18 place = EMSG; 19 return (-1); 20 } 21 if (place[1] && *++place == '-' /* found "--" */ 22 && place[1] == '\0') { 23 ++optind; 24 place = EMSG; 25 return (-1); 26 } 27 } /* option letter okay? */ 28 if ((optopt = (int)*place++) == (int)':' || 29 !(oli = strchr(ostr, optopt))) { 30 /* 31 * if the user didn't specify '-' as an option, 32 * assume it means -1. 33 */ 34 if (optopt == (int)'-') 35 return (-1); 36 if (!*place) 37 ++optind; 38 if (opterr && *ostr != ':') 39 (void)fprintf(stderr, 40 "%s: illegal option -- %c\n", __progname, optopt); 41 return (BADCH); 42 } 43 if (*++oli != ':') { /* don't need argument */ 44 optarg = NULL; 45 if (!*place) 46 ++optind; 47 } 48 else { /* need an argument */ 49 if (*place) /* no white space */ 50 optarg = place; 51 else if (nargc <= ++optind) { /* no arg */ 52 place = EMSG; 53 if (*ostr == ':') 54 return (BADARG); 55 if (opterr) 56 (void)fprintf(stderr, 57 "%s: option requires an argument -- %c\n", 58 __progname, optopt); 59 return (BADCH); 60 } 61 else /* white space */ 62 optarg = nargv[optind]; 63 place = EMSG; 64 ++optind; 65 } 66 return (optopt); /* dump back option letter */ 67 }
還以為是什么新穎的寫法, 原來是C最原始的寫法K&R C風格, 而我們現在寫的都是ANSI C風格, 原諒我讀書少, 沒有認真讀過那些C 的經典書籍
ANSI C 對 K&R C 的修訂
(本段根據《C Programming Language》和C語言標准整理。不求完整,希望列出最常見的差異)
- 對於源文件內部的標識符,有效的最小長度擴充到31個字符。文件間連接時,標識符的最小有效長度仍然為6個字符。(許多實現都支持更大的長度)
- 增加了幾個新關鍵字:void,const,volatile,signed,enum。拋棄了老關鍵字entry。
- 在換意字符 \ 之后寫非規定的序列,其作用確定為無定義。
- 規定8和9都不是八進制數的合法字符。
- 引進了數的后綴字符:整數的U和L,浮點數的F和L。
- 規定連續出現的字符串常量將被拼接在一起。
- 引進了“寬字符”的概念。
- 將字符也確定為帶符號(signed)和不帶符號(unsigned)的。
- 丟棄了long float(原來作為double的同義詞)。
- 引入了void類型,用 (void*) 表示通用指針的類型(過去人們通常用 (char*))。
- 對算術類型規定了最小表示范圍。要求每個C語言系統用頭文件(<limits.h>;和<float.h>;)說明實現中的具體規定。
- 引進了枚舉定義enum。
- 采用了來自C++的類型修飾符,如const。
- 規定字符串常量是不可修改的。
- 改變了算術類型的隱含轉換規則。
- 刪去了一些過時賦值運算符,如 =+。規定賦值運算符都是基本單詞,如 += 之間不能有空格分隔。
- 引進了與一元 - 運算符對應的一元 + 運算符。
- 指向函數的指針可以直接放在函數調用的位置,不必顯式地寫間接操作。
- 允許結構地整體賦值,作為函數參數和返回值傳遞。
- 允許將取地址運算符作用於數組,得到的是指向有關數組的指針。
- 標准規定 sizeof 運算符的返回值為 size_t 類型(某個無符號整型),這一類型在標准頭文件<stddef.h>;里定義。同時在那里定義的還有 ptrdiff_t 類型,它是指針減運算的結果類型。
- 規定取地址運算符不能作用於 register 變量。
- 規定移位表達式的類型為其左運算對象的類型。
- 允許建立指向過數組末元素一個位置的指針,以及對它的算術運算和關系運算。
- (從C++)引進了包含參數類型的函數原型概念,引進了變長參數表函數的概念。仍允許老的形式,但僅僅是作為過時形式保留。
- 標准規定任何局部聲明的作用域僅僅是當前的塊(復合語句)。
- 規定函數參數作為加入函數體(復合語句)的聲明,因此不能用變量聲明去覆蓋。
- 有關名字空間的規定:所有結構、聯合和枚舉標記在一個名字空間里,標號是另一個名字空間。
- 聯合變量在定義時也可以初始化,規定初始化其第一個成分。
- 自動結構、聯合和數組也可以初始化,但限制其初始化方式(其中只能包含常量表達式)。
- 帶大小描述的字符數組也可以用大小與之相同的字符串常量初始化(結束的 \0 被刪除)。
- 開關語句的控制表達式和case標號可以是任何整型的(包括字符類型)。
參考: