??C++是C語言的一個超集。C++有一個眾所周知的特性:對C語言的高度兼容。這樣的兼容性不僅體現在程序員可以較為容易地將C代碼“升級”為C++代碼上,也體現在C代碼可以被C++的編譯器所編譯上。 ??C++的第一個標準是1998年制定的C++98,而C的第二個官方標準是1999年制定C99,C99制定時,借鑒了很多C++98中的特性,2011年,新C++標準,C++11發布,增添了新特性,同時兼容C99中的特性。
??所以C與C++的最大區別在于它們的用于解決問題的思想方法不一樣。之所以說C++比C更先進,是因為“設計這個概念已經被融入到C++之中”。
??1951年,IBM的Jhon Backus(Fortran開發小組組長)基于匯編語言著手研發Fortran語言。 ??1960年,圖靈獎獲得者Alan J.Perlis在巴黎舉行的有全世界一流軟件專家參加的討論會上,發表了”算法語言Algol 60報告”,確定了程序設計語言Algol 60。Algol60語言的第一個編譯器由Edsger W. Dijkstra來實現。1962年,Alan J.Perlis又對Algol 60進行了修正。Algo60語言,是從Fortran演化的一個標準,目的是標準化一種數值計算語言。 ??1963年,劍橋大學將ALGOL 60語言發展成為CPL語言(Combined PRogramming Language)。 ??1967年,劍橋大學的Matin Richards對CPL語言進行了簡化,于是產生了BCPL語言。 ??1970年,美國貝爾實驗室的Ken Thompson將BCPL進行了修改,并為它起了一個有趣的名字“B語言”(最初是為Unix設計的)。并且他用B語言寫了第一個UNIX操作系統(第二版)。 ??1973年,美國貝爾實驗室的D.M. Ritchie在B語言的基礎上最終設計出了一種新的語言,他取了BCPL的第二個字母作為這種語言的名字,這就是C語言。此后,其用C語言對Unix進行了重寫(第三版)。
??最初,C語言沒有官方標準。1978年Brian W.Kernighian和Dennis M.Ritchie出版了名著《The C Programming Language》,從而使C語言成為目前世界上流行最廣泛的高級程序設計語言。而這本書附錄中的C Referrence Manual成為了事實上的C語言標準,被人們稱為K&R C或者Classic C。但是,該附錄中只定義了C語言,卻沒有定義C庫。由于C的出現離不開Unix,因此,Unix上實現的庫成為了一個C語言事實上的標準庫。 ??隨著C語言的日益流行,美國國家標準化組織(ANSI)在1983年成立了一個委員會(X3J11),以制定C語言標準。該標準于1989年正式被批準采用。它就是ANSI C標準。該標準定義了C語言標準和C的標準庫。1990年,國際標準化組織(ISO)也要制定了一個C標準,以使C語言在國際上統一標準,方便使用,他們直接采用了ANSI C標準,發布了標準文件:ISO/IEC 9899-1990 Programming languages – C。最終第一版的C標準被稱為C98或C90。算是C語言的第一個官方標準。由于ANSI C出現較早,該標準也稱為 ANSI C。 ??1994年,ISO 對C語言標準的修訂工作正式開始。1999年12月1日,國際標準化組織(ISO)和國際電工委員會(IEC)旗下的C語言標準委員會(ISO/IEC JTC1/SC22/WG14)正式發布了標準文件: ISO/IEC 9899:1999 - Programming languages – C。這就是大家熟知的C99標準。這成為了C語言的第二個官方標準。 ??C99的修訂為C語言引入了大量新的特性,其借鑒了C++98標準一些特性。然而,如今不是所有C的編譯器都支持C99標準,而完全或幾乎完全支持C99標準的主流編譯器有:GCC、Clang、Intel C++ Compiler等。另外,Visual Studio2013也部分支持了C99語法特征。 ??C99標準之后,新的C語言標準是國際標準化組織(ISO)和國際電工委員會(IEC)在2011年12月8日正式發布的C11標準,官方正式名為ISO/IEC 9899:2011
??C標準由ISO和IEC旗下的C語言標準委員會(ISO/IEC JTC1/SC22/WG14)編寫,在其官方網站(http://www.open-std.org/)上可以找到標準的草稿,草稿是免費的!
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 是對 .c,.d 賦值的
字符串里面,/u 支持 unicode 的字符支持 16 進制的浮點數的描述所以 printf scanf 的格式化串多支持了 ll / LL對應新的 long long 類型。浮點數的內部數據描述支持了新標準,這個可以用 #pragma 編譯器指定除了已經有的 line file 以外,又支持了一個 func 可以得到當前的函數名對于非常數的表達式,也允許編譯器做化簡修改了對于 / % 處理負數上的定義,比如老的標準里 -22 / 7 = -3, -22 % 7 = -1 而現在 -22 / 7 = -4, -22 % 7 = 6取消了不寫函數返回類型默認就是 int 的規定允許 struct 定義的最后一個數組寫做 [] 不指定其長度描述const const int i; 將被當作 const int i; 處理增加和修改了一些標準頭文件。輸入輸出對寬字符還有長整數等做了相應的支持??關鍵字restrict只用于限定指針;該關鍵字用于告知編譯器,所有修改該指針所指向內容的操作全部都是基于(base on)該指針的,即不存在其它進行修改操作的途徑;這樣的后果是幫助編譯器進行更好的代碼優化,生成更有效率的匯編代碼。restrict指針指針主要用做函數變元,或者指向由malloc()函數所分配的內存變量。restrict數據類型不改變程序的語義。 ??如果某個函數定義了兩個restrict指針變元,編譯程序就假定它們指向兩個不同的對象,memcpy()函數就是restrict指針的一個典型應用示例。 ??C89中memcpy()函數原型如下: void *memcpy (void *s1, const void *s2, size_t size);
??如果s1和s2所指向的對象重疊,其操作就是未定義的。memcpy()函數只能用于不重疊的對象。 ??C99中memcpy()函數原型如下: void *memcpy(void *restrict s1, const void *restrict s2,size_t size);
??通過使用restrict修飾s1和s2 變元,可確保它們在該原型中指向不同的對象。 ??但要注意:restrict是C99中新增的關鍵字,在C89和C++中都不支持,在gcc中可以通過-std=c99來得到對它的支持。
??內聯函數除了保持結構化和函數式的定義方式外,還能使程序員寫出高效率的代碼。函數的每次調用與返回都會消耗相當大的系統資源,尤其是當函數調用發生在重復次數很多的循環語句中時。一般情況下,當發生一次函數調用時,變元需要進棧,各種寄存器內存需要保存。當函數返回時,寄存器的內容需要恢復。如果該函數在代碼內進行聯機擴展,當代碼執行時,這些保存和恢復操作旅游活動會再發生,而且函數調用的執行速度也會大大加快。函數的聯機擴展會產生較長的代碼,所以只應該內聯對應用程序性能有顯著影響的函數以及長度較短的函數
??值是0或1。C99中增加了用來定義bool、true以及false宏的頭文件
??C99標準中定義的復數類型如下:
float_Complex; float_Imaginary; double_Complex; double_Imaginary; long double_Complex; long double_Imaginary;??
??C99標準中引進了long long int(-(2e63 - 1)至2e63 - 1)和unsigned long long int(0 - 2e64 - 1)。long long int能夠支持的整數長度為64位。對應的常量后綴是ll/ull/LL/ULL;格式化輸入輸出為%lld,%llu,%llx……
??C99中,程序員聲明數組時,數組的維數可以由任一有效的整型表達式確定,包括只在運行時才能確定其值的表達式,這類數組就叫做可變長數組,但是只有局部數組才可以是變長的。 ??可變長數組的維數在數組生存期內是不變的,也就是說,可變長數組不是動態的。可以變化的只是數組的大小。
void func(int n){ int vla[n]; printf("int vla[n] = %d/n", sizeof(vla));}變長數組有一些限制:變長數組必須是自動存儲類的,意味著它們必須在函數內部或作為函數參數聲明,而且聲明時不可以進行初始化。C99標準規定,可以省略函數原型中的名稱,但是如果省略名稱,則需要用星號來代替省略的維數:int sum2d(int , int, int ar[*][*]);
// 只能用在函數聲明中??在C99中,如果需要使用數組作為函數變元,可以在數組聲明的方括號內使用static關鍵字,這相當于告訴編譯程序,變元所指向的數組將至少包含指定的元素個數。也可以在數組聲明的方括號內使用restrict,volatile,const
關鍵字,但只用于函數變元。如果使用restrict,指針是初始訪問該對象的惟一途徑。如果使用const,指針始終指向同一個數組。使用volatile沒有任何意義。(類型限定詞和static關鍵字只能用于具有數組類型的函數形參的第一維中)。由于形參中的VLA被自動調整為等效的指針,因此這些類型限定詞實際上限定的是一個指針,例如:
??// 行注釋也是從C++過來的東西。引入了單行注釋標記 “//” , 可以象C++一樣使用這種注釋了。//注釋另外一個最大的好處還是在于排版方便。 ??/* / 注釋是不支持嵌套的,所以只要里頭出現一個/就會導致注釋結束。不過這樣也帶來了一個有點可怕的陷阱,比如原來用/* */注釋的宏:
#define macro(arg1, arg2) / func(arg1, /* xxxxxxx */ / arg2 /* xxxxxxx */ / )你要是改成這樣:
#define macro(arg1, arg2) / func(arg1, // xxxxxxx / arg2 // xxxxxxx / )這就杯具了~~因為這樣等價于:
#define macro(arg1, arg2) func(arg1, // xxxxxxx arg2 // xxxxxxx )arg2就落入第一個//的魔掌,變成注釋了~~ ??總得來說,用//寫注釋肯定是比較方便的。只要能保證別在一個文件里面一會兒用/* */做行注釋,一會兒用//做行注釋就行了。 建議所有的單行注釋都可以用//搞。而文檔化注釋(函數頭部、文件頭部或者重要數據結構頭部的那些注釋),還是建議用正統的格式來寫:
/** * xxxxxxx * xxxxxxx */另外最好別用//來壘多行注釋。
??解除了原先必須在block的第一條語句之前聲明變量的限制:現在C99也和C++一樣,可以在代碼中隨時聲明變量了。
#include <stdio.h>int main(void){ int num1 = 3; int num1 = 3; printf("%d/n", num1); int num2 = 10; // 變量定義 printf("%d/n", num2); return(0);}??其實混合聲明對于編碼的重要意義在于它對提高代碼的可讀性方面幫助很大。在C89里面,稍微復雜一點的函數中通常會看到這樣的壯觀景象:
int load_elf_file(const char *filename, int argc, int argv, int *retcode){ int elf_exec_fileno; int i, retval; uint k, elf_bss, elf_brk, elf_entry; uint start_code, end_code, end_data; struct elf_phdr *elf_ppnt, *elf_phdata; struct elfhdr elf_ex; struct file *file; ...;}??這個就是C89必須在Block第一條語句之前聲明變量帶來的后果,不管一個變量是否一直到Block的最后一行才被用到,你也不得不在一開始就聲明它。
??宏可以帶變元,在宏定義中用省略號(…)表示。內部預處理標識符VA_ARGS決定變元將在何處得到替換。變參宏的最大好處是可以讓你很容易地用宏來封裝一些帶變參的函數(主要是打印函數) 如可以這樣寫一個輸出到stderr的宏:
#define print_err(...) fprintf(stderr, __VA_ARGS__) // 宏參數里面“...”的部份會展開到__VA_ARGS__處。??如果在VA_ARGS前面加上##,就可以寫出允許變參部份為空的變參宏。比如我自己常用的調試信息打印宏:
#define debug(fmt, ...) / printf("[DEBUG] %s:%d <%s>: " fmt, / __FILE__, __LINE__, __func__, ##__VA_ARGS__)??##VA_ARGS表示變參“…”部份允許為空。當變參部份為空時VA_ARGS會展開成空字符串,并且##前面那個逗號也會在展開時去掉。于是你可以這樣調用這個宏:debug(“Hello”);
??C99引入了在程序中定義編譯指令的另外一種方法:_Pragma運算符。格式如下: _Pragma("directive")
??其中directive是要滿打滿算的編譯指令。_Pragma運算符允許編譯指令參與宏替換。 ??如果字符串文字具有L前綴,則刪除該前綴。 ??刪除前導和結尾雙引號。 ??用雙引號替換每個換碼序列’。 ??用單個反斜杠替換每個換碼序列/
STDC FP_CONTRACT ON/OFF/DEFAULT 若為ON,浮點表達式被當做基于硬件方式處理的獨立單元。默認值是定義的工具。 STDC FEVN_access ON/OFF/DEFAULT 告訴編譯程序可以訪問浮點環境。默認值是定義的工具。 STDC CX_LIMITED_RANGE ON/OFF/DEFAULT 若值為ON,相當于告訴編譯程序某程序某些含有復數的公式是可靠的。默認是OFF。
STDC_HOSTED 若操作系統存在,則為1 STDC_VERSION 199991L或更高。代表C的版本 STDC_IEC_599 若支持IEC 60559浮點運算,則為1 STDC_IEC_599_COMPLEX 若支持IEC 60599復數運算,則為1 STDC_ISO_10646 由編譯程序支持,用于說明ISO/IEC 10646標準的年和月格式:yyymmmL
??C99中,程序員可以在for語句的初始化部分定義一個或多個變量,這些變量的作用域僅于本for語句所控制的循環體內。在C89中,這樣是不可以的,具體可以在VC6中驗證(VC6支持到C89)。for循環的初始化語句中聲明的任何變量的作用域是整個循環(包括控制和迭代表達式)。 如下:
for (int i=0; i<10; i++){ //loop body};??C99復合賦值中,可以指定對象類型的數組、結構或聯合表達式。當使用復合賦值時,應在括弧內指定類型,后跟由花括號圍起來的初始化列表;若類型為數組,則不能指定數組的大小。建成的對象是未命名的。 例: double *fp = (double[]) {1.1, 2.2, 3.3};
??該語句用于建立一個指向double的指針fp,且該指針指向這個3元素數組的第一個元素。 在文件域內建立的復合賦值只在程序的整個生存期內有效。在模塊內建立的復合賦值是局部對象,在退出模塊后不再存在。
??C99具有一個稱為伸縮型數組成員(flexible array member)的新特性。結構中的最后一個元素允許是未知大小的數組,這就叫做柔性數組成員。利用這一新特性可以聲明最后一個成員是一個具有特殊屬性的數組的結構體。該數組成員的特殊屬性之一是它不立即存在。第二個特殊屬性是您可以編寫適當的代碼使用這個伸縮型數組成員,就像它確實存在并且擁有您需要的任何數目的元素一樣。柔性數組成員在做變長的報文或字符串處理時極為好用,也是一個幾乎所有的C碼農都應該掌握的技巧。 聲明一個伸縮型數組成員的規則: - 伸縮型數組成員必須是最后一個數組成員。 - 結構中必須至少有一個其他成員。 - 伸縮型數組就像普通數組一樣被聲明,但是它的方括號是空的。 比如:
typedef struct { int count; char Word[]; // 只能放在末尾,等價于gcc的char word[0]} word_counter_t;注意:
sizeof返回的這種結構大小不包括柔性數組的內存直接聲明帶有伸縮數組成員結構體的變量沒有任何意義,因為伸縮數組沒有內存,例如:word_counter_t wd; // 這里變量wd中沒有word包含柔性數組成員的結構用malloc()函數進行內存的動態分配,并且分配的內存應該大于結構的大小,以適應柔性數組的預期大小。當給其指針動態分配內存空間時,多余的空間會分配給scores數組??C99中,該特性對經常使用稀疏數組的程序員十分有用。簡單來說,就是在初始化結構體和數組時,可以通過指定具體成員名或數組下標來賦初值。 用于數組的格式: [index] = vol; // 其中,index表示數組的下標,vol表示本數組元素的初始化值。 例如: int x[10] = {[0] = 10, [5] = 30}; 其中只有x[0]和x[5]得到了初始化
用于結構或聯合的格式如下: .成員名 = vol; // 其中, vol表示本數組元素的初始化值。
例如: struct example{ int k, m, n; } object = {.m = 10, .n = 200};
注意:該方法只能用在定義時初始化,不能再后續使用
??C99中printf()和scanf()函數系列引進了處理long long int和unsigned long long int數據類型的特性。long long int 類型的格式修飾符是ll。在printf()和scanf()函數中,ll適用于d, i, o, u 和x格式說明符。另外,C99還引進了hh修飾符。當使用d, i, o, u和x格式說明符時,hh用于指定char型變元。ll和hh修飾符均可以用于n說明符。 ??格式修飾符a和A用在printf()函數中時,結果將會輸出十六進制的浮點數。格式如下:[-]0xh, hhhhp + d 使用A格式修飾符時,x和p必須是大寫。A和a格式修飾符也可以用在scanf()函數中,用于讀取浮點數。調用printf()函數時,允許在%f說明符前加上l修飾符,即%lf,但不起作用。
C89中標準的頭文件
<assert.h> 定義宏assert()<ctype.h> 字符處理<errno.h> 錯誤報告<float.h> 定義與實現相關的浮點值<limits.h> 定義與實現相關的各種極限值<locale.h> 支持函數setlocale()<locale.h> 數學函數庫使用的各種定義<setjmp.h> 支持非局部跳轉<signal.h> 定義信號值<stdarg.h> 支持可變長度的變元列表<stddef.h> 定義常用常數<stdio.h> 支持文件輸入和輸出<stdlib.h> 其他各種聲明<string.h> 支持串函數<time.h> 支持系統時間函數C99新增的頭文件和庫
<complex.h> 支持復數算法<fenv.h> 給出對浮點狀態標記和浮點環境的其他方面的訪問<inttypes.h> 定義標準的、可移植的整型類型集合。也支持處理最大寬度整數的函數<iso646.h> 在1995年第一次修訂時首次引進,用于定義對應各種運算符的宏<stdbool.h> 支持布爾數據類型類型。定義宏bool,以便兼容于C++<stdint.h> 定義標準的、可移植的整型類型集合。該文件包含在<inttypes.h>中<tgmath.h> 定義一般類型的浮點宏<wchar.h> 在1995年第一次修訂時首次引進,用于支持多字節和寬字節函數<wctype.h> 在1995年第一次修訂時首次引進,用于支持多字節和寬字節分類函數??用于指出func所存放的函數名,類似于字符串賦值。
??C99中,如果同一類型限定符在同一說明符限定符列表中出現多次(無論直接出現還是通過一個或多個typedef),行為與該類型限定符僅出現一次時相同。 ??在C90中,以下代碼會導致錯誤:
const const int a; int main(void){ return(0);}但是,對于C99,C編譯器接受多個限定符。
??現在,關鍵字static可以出現在函數聲明符中及參數的數組聲明符中,表示編譯器至少可以假定許多元素將傳遞到所聲明的函數中。使優化器能夠作出以其他方式無法確定的假定。
C編譯器將數組參數調整為指針,因此void foo(int a[]) 與void foo(int *a) 相同。 如果您指定void foo(int * restrict a); 等類型限定符,則C 編譯器使用實質上與聲明限定指針相同的數組語法void foo(int a[restrict]); 表示它。 C編譯器還使用static限定符保留關于數組大小的信息。例如,如果您指定void foo(int a[10]),則編譯器仍將它表達為void foo(int *a)。按以下所示使用static限定符:void foo(int a[static 10]),讓編譯器知道指針a不是NULL,并且使用它可訪問至少包含十個元素的整數數組。1.放寬的轉換限制
限制 | C89標準 | C99標準 |
---|---|---|
數據塊的嵌套層數 | 15 | 127 |
條件語句的嵌套層數 | 8 | 63 |
內部標識符中的有效字符個數 | 31 | 63 |
外部標識符中的有效字符個數 | 6 | 31 |
結構或聯合中的成員個數 | 127 | 1023 |
函數調用中的參數個數 | 31 | 127 |
2. 不再支持隱含式的int規則 每個聲明中的聲明說明符中應至少指定一個類型說明符,現在不支持沒有類型就默認是int的聲明語句。比如在C89中, auto i = 0;是合法的 3. 刪除了隱含式函數聲明 4. 對返回值的約束。C99中,非空類型函數必須使用帶返回值的return語句 5. 擴展的整數類型
擴展類型 | 含義 |
---|---|
int16_t | 整數長度為精確16位 |
int_least16_t | 整數長度為至少16位 |
int_fast32_t | 最穩固的整數類型,其長度為至少32位 |
intmax_t | 最大整數類型 |
uintmax_t | 最大無符號整數類型 |
6. 對整數類型提升規則的改進。C89中,表達式中類型為char,short int或int的值可以提升為int或unsigned int類型。 7. C99中,每種整數類型都有一個級別。例如:long long int 的級別高于int, int的級別高于char等。在表達式中,其級別低于int或unsigned int的任何整數類型均可被替換成int或unsigned int類型。 ??但是各個公司對C99的支持所表現出來的興趣不同。當GCC和其它一些商業編譯器支持C99的大部分特性的時候,微軟和Borland卻似乎對此不感興趣。
??1967 年,Simula語言中第一次出現了面向對象 (OO) 的概念,但由于當時軟件規模還不大,技術也還不太成熟,面向對象的優勢并未發揮出來。1980年,Smalltalk-80出現后,面向對象技術才開始發揮魅力。 ??1979 年,Bjarne Stroustrup 借鑒 Simula中”Class” 的概念,開始著手“C with Classes”的研發工作,“C with Classes”表明這種新語言是在C基礎上研發的,是C語言的超集。新語言的初始版本除了包括C語言的基本特征之外,還具備類、簡單繼承、內聯機制、函數默認參數以及強類型檢查等特性。Bjarne Stroustrup的第一款“C with classes”編譯器叫Cfront(由“C with Classes”編寫),這個名字源自一個叫做Cpre的C編譯器。Cfront的機理是把“C with classes”的代碼翻譯成原生C代碼。 ??1983年,“C with Classes”語言更名為C++。C語言中“++”運算子的作用是對一個變量進行遞增操作,由此我們多少可以知曉Stroustrup對這種新語言的定位。這個時期,許多重要的特性被加入,其中包括虛函數、函數重載、引用機制(符號為&)、const關鍵字以及雙斜線的單行注釋(從BCPL語言引入)。 ??1986 年,B.Stroustrup 出版了《The C++ Programming Language》第一版,這時 C++ 已經開始受到關注,B.Stroustrup 被稱為 C++之父(Creator of C++)。 ??1989 年,負責 C++ 標準化的 ANSI X3J16掛牌成立。1989年,C++再次版本更新,這次更新引入了多重繼承、保護成員以及靜態成員等語言特性。 ??1990 年,B.Stroustrup 出版了《The Annotated C++ Reference Manual》(簡稱 ARM),由于當時還沒有 C++ 標準,ARM 成了事實上的標準。1990 年,Template(模板) 和 Exception(異常) 加入到了 C++ 中,使 C++ 具備了泛型編程(Generic Programming)和更好的運行期錯誤處理方式。 ??1991 年,負責 C++ 語言國際標準化的技術委員會工作組 ISO/IEC JTC1/SC22/WG21 召開了第一次會議,開始進行 C++ 國際標準化的工作。從此,ANSI 和 ISO 的標準化工作保持同步,互相協調。1993 年,RTTI(運行期類型識別)和Namespace(名字空間)加入到 C++ 中。1994年,C++ 標準草案出臺。 B.Stroustrup 出版了《The Design and Evolution of C++》(簡稱 D&E)。本來,C++ 標準已接近完工,這時 STL(標準模板庫) 的建議草案被提交到標準委員會,對 STL 標準化的討論又一次推遲了 C++ 標準的出臺。 ??1998年,C++標準委員會發布了C++語言的第一個國際標準—ISO/IEC 14882:1998,該標準即為大名鼎鼎的C++98。C++98的提出,《The Annotated C++ Reference Manual》功不可沒。同時,1979年開始研發的標準模板庫(Standard Template Library,STL)也被納入了該版標準中。ANSI 和 ISO 終于先后批準 C++ 語言成為美國國家標準和國際標準。 ??2003年,標準委員會針對98版本中存在的諸多問題進行了修訂,并沒有增加新的特性,修訂后發布了C++03。 C++11,之前被稱作C++0x,即ISO/IEC 14882:2011,是目前的C++編程語言的第三版正式標準。它取代第二版標準ISO/IEC 14882:2003(第一版ISO/IEC 14882:1998發布于1998年,第二版于2003年發布,分別通稱C++98以及C++03,兩者差異很小)。新的標準包含了幾個核心語言增加的新特性,而且擴展C++標準程序庫,并入了大部分的C++ Technical Report 1程序庫(數學的特殊函數除外)。為了兼容C語言,C++11將對以下C99特性的支持也都納入了新標準中:
__func__預定義標識符_Pragma 操作符不定參數宏定義以及__VA_ARGS__寬窄字符串連接long long類型略
新聞熱點
疑難解答
圖片精選