在很大程度上,C++是C的超集,這意味著一個有效的C程序也是一個有效的C++程序。
?C和C++的主要區(qū)別是,C++支持許多附加特性。但是,C++中有許多規(guī)則與C稍有不同。這些不同使得C程序作為C++程序編譯時可能以不同的方式運行或根本不能運行。
?本節(jié)著重討論這些區(qū)別。如果使用C++的編譯器編譯C程序,就知道這些不同之處。雖然C和C++的區(qū)別對本書的示例影響很小,但如果把C代碼作為C++程序編譯的話,會導(dǎo)致產(chǎn)生錯誤的消息。C99標準的發(fā)布使得問題更加復(fù)雜,因為有些情況下使得C更接近C++。 ? ?
?例如,C99標準允許在代碼中的任意處進行聲明,而且可以識別//注釋指示符。在其他方面,C99使其與C++的差異變大。
例如,新增了變長數(shù)組和關(guān)鍵字restrict。C11縮小了與C++的差異。
例如,引進了char16_t類型,新增了關(guān)鍵字_Alignas,新增了alignas宏與C++的關(guān)鍵字匹配。C11仍處于起步階段,許多編譯器開發(fā)商甚至都沒有完全支持C99。 ? ? ? ?
?我們要了解C90、C99、C11之間的區(qū)別,還要了解C++11與這些標準之間的區(qū)別,以及每個標準與C標準之間的區(qū)別。這部分主要討論C99、C11和C++之間的區(qū)別。當(dāng)然,C++也正在發(fā)展,因此,C和C++的異同也在不斷變化。 ?
2、函數(shù)原型 ?
在C++中,函數(shù)原型必不可少,但是在C中是可選的。這一區(qū)別在聲明一個函數(shù)時讓函數(shù)名后面的圓括號為空,就可以看出來。在C中,空圓括號說明這是前置原型,但是在C++中則說明該函數(shù)沒有參數(shù)。也就是說,在C++中,intslice();和int slice(void);相同。例如,下面舊風(fēng)格的代碼在C中可以接受,但是在C++中會產(chǎn)生錯誤: ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
int slice();
int main()
{
...
slice(20, 50);
...
}
int slice(int a, int b)
{
...
}
?在C中,編譯器假定用戶使用舊風(fēng)格聲明函數(shù)。在C++中,編譯器假定slice()與slice(void)相同,且未聲明slice(int,int)函數(shù)。 ?另外,C++允許用戶聲明多個同名函數(shù),只要它們的參數(shù)列表不同即可。
?3、char常量
?C把char常量視為int類型,而C++將其視為char類型。例如,考慮下面的語句:
- ?
char ch = 'A';
?在C中,常量'A'被儲存在int大小的內(nèi)存塊中,更精確地說,字符編碼被儲存為一個int類型的值。相同的數(shù)值也儲存在變量ch中,但是在ch中該值只占內(nèi)存的1字節(jié)。 ?在C++中,'A'和ch都占用1字節(jié)。它們的區(qū)別不會影響本書中的示例。但是,有些C程序利用Char常量被視為int類型這一特性,用字符來表示整數(shù)值。例如,如果一個系統(tǒng)中的int是4字節(jié),就可以這樣編寫C代碼: ?
- ?
int x = 'ABCD'; /*對于int是4字節(jié)的系統(tǒng),該語句出現(xiàn)在C程序中沒問題,但是出現(xiàn)在C++程序中會出錯 */
?'ABCD'表示一個4字節(jié)的int類型值,其中第1個字節(jié)儲存A的字符編碼,第2個字節(jié)儲存B的字符編碼,以此類推。注意,'ABCD'和"ABCD"不同。前者只是書寫int類型值的一種方式,而后者是一個字符串,它對應(yīng)一個5字節(jié)內(nèi)存塊的地址。考慮下面的代碼: ?
- ?
- ?
- ?
int x = 'ABCD';
char c = 'ABCD';
printf("%d %d %c %c ", x, 'ABCD', c, 'ABCD');
?
在我們的系統(tǒng)中,得到的輸出如下:
?
- ?
1094861636 1094861636 D D
?該例說明,如果把'ABCD'視為int類型,它是一個4字節(jié)的整數(shù)值。但是,如果將其視為char類型,程序只使用最后一個字節(jié)。在我們的系統(tǒng)中,嘗試用%s轉(zhuǎn)換說明打印'ABCD'會導(dǎo)致程序崩潰,因為'ABCD'的數(shù)值(1094861636) 已超出該類型可表示的范圍。 ?可以這樣使用的原因是C提供了一種方法可單獨設(shè)置int類型中的每個字節(jié),因為每個字符都對應(yīng)一個字節(jié)。但是,由于要依賴特定的字符編碼,所以更好的方法是使用十六進制的整型常量,因為每兩位十六進制數(shù)對應(yīng)一個字節(jié)。第15章詳細介紹過相關(guān)內(nèi)容(C的早期版本不提供十六進制記法,這也許是多字符常量技術(shù)首先得到發(fā)展的原因)。 ?
4、const限定符 ?
在C中,全局的const具有外部鏈接,但是在C++中,具有內(nèi)部鏈接。也就是說,下面C++的聲明: ?
- ?
const double PI = 3.14159;
?相當(dāng)于下面C中的聲明: ?
- ?
static const double PI = 3.14159;
?假設(shè)這兩條聲明都在所有函數(shù)的外部。C++規(guī)則的意圖是為了在頭文件更加方便地使用const。如果const變量是內(nèi)部鏈接,每個包含該頭文件的文件都會獲得一份const變量的備份。如果const變量是外部鏈接,就必須在一個文件中進行定義式聲明,然后在其他文件中使用關(guān)鍵字extern進行引用式聲明。
?順帶一提,C++可以使用關(guān)鍵字extern使一個const值具有外部鏈接。所以兩種語言都可以創(chuàng)建內(nèi)部鏈接和外部鏈接的const變量。它們的區(qū)別在于默認使用哪種鏈接。 ?
另外,在C++中,可以用const來聲明普通數(shù)組的大小: ?
- ?
- ?
const int ARSIZE = 100;
double loons[ARSIZE]; /* 在C++中,與double loons[100];相同 */
?當(dāng)然,也可以在C99中使用相同的聲明,不過這樣的聲明會創(chuàng)建一個變長數(shù)組。在C++中,可以使用const值來初始化其他const變量,但是在C中不能這樣做: ?
- ?
const double RATE = 0.06; // C++和C都可以const double STEP = 24.5; // C++和C都可以const?double?LEVEL?=?RATE?*?STEP;????//?C++可以,C不可以
?5、結(jié)構(gòu)和聯(lián)合 ?
聲明一個有標記的結(jié)構(gòu)或聯(lián)合后,就可以在C++中使用這個標記作為類型名: ?
- ?
struct duo{ int a; int b;};struct duo m; /* C和C++都可以 */duo n; /* C不可以,C++可以*/
?結(jié)果是結(jié)構(gòu)名會與變量名沖突。例如,下面的程序可作為C程序編譯,但是作為C++程序編譯時會失敗。因為C++把printf()語句中的duo解釋成結(jié)構(gòu)類型而不是外部變量: ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
#include
float duo = 100.3;
int main(void)
{
struct duo { int a; int b;};
struct duo y = { 2, 4};
printf ("%f ", duo); /* 在C中沒問題,但是在C++不行 */
return 0;
}
?在C和C++中,都可以在一個結(jié)構(gòu)的內(nèi)部聲明另一個結(jié)構(gòu): ?
- ?
- ?
- ?
- ?
- ?
struct box
{
struct point {int x; int y; } upperleft;
struct point lowerright;
};
? ?在C中,隨后可以使用任意使用這些結(jié)構(gòu),但是在C++中使用嵌套結(jié)構(gòu)時要使用一個特殊的符號: ?
- ?
- ?
- ?
struct box ad; /* C和 C++都可以 */
struct point dot; /* C可以,C++不行 */
box::point dot; /* C不行,C++可以 */
?6、枚舉
?C++使用枚舉比C嚴格。特別是,只能把enum常量賦給enum變量,然后把變量與其他值作比較。不經(jīng)過顯式強制類型轉(zhuǎn)換,不能把int類型值賦給enum變量,而且也不能遞增一個enum變量。下面的代碼說明了這些問題: ?
- ?
- ?
- ?
- ?
- ?
- ?
enum sample {sage, thyme, salt, pepper};
enum sample season;
season = sage; /* C和C++都可以 */
season = 2; /* 在C中會發(fā)出警告,在C++中是一個錯誤 */
season = (enum sample) 3; /* C和C++都可以*/
season++;???????????????????/*?C可以,在C++中是一個錯誤?*/
?另外,在C++中,不使用關(guān)鍵字enum也可以聲明枚舉變量: ?
- ?
- ?
enum sample {sage, thyme, salt, pepper};
sample?season;????/*?C++可以,在C中不可以?*/
?與結(jié)構(gòu)和聯(lián)合的情況類似,如果一個變量和enum類型的同名會導(dǎo)致名稱沖突。 ?
7、指向void的指針
?C++可以把任意類型的指針賦給指向void的指針,這點與C相同。但是不同的是,只有使用顯式強制類型轉(zhuǎn)換才能把指向void的指針賦給其他類型的指針。下面的代碼說明了這一點: ?
- ?
- ?
- ?
- ?
- ?
- ?
int ar[5] = {4, 5, 6,7, 8};
int * pi;
void * pv;
pv = ar; /* C和C++都可以 */
pi = pv; /* C可以,C++不可以 */
pi?=?(int?*?)?pv;???/*?C和C++都可以?*/
?C++與C的另一個區(qū)別是,C++可以把派生類對象的地址賦給基類指針,但是在C中沒有這里涉及的特性。 ?
?8、布爾類型
?在C++中,布爾類型是bool,而且ture和false都是關(guān)鍵字。在C中,布爾類型是_Bool,但是要包含stdbool.h頭文件才可以使用bool、true和false。
?9、可選拼寫
?在C++中,可以用or來代替||,還有一些其他的可選拼寫,它們都是關(guān)鍵字。在C99和C11中,這些可選拼寫都被定義為宏,要包含iso646.h才能使用它們。
?10、寬字符支持
?在C++中,wchar_t是內(nèi)置類型,而且wchar_t是關(guān)鍵字。在C99和C11中,wchar_t類型被定義在多個頭文件中(stddef.h、stdlib.h、wchar.h、wctype.h)。與此類似,char16_t和char32_t都是C++11的關(guān)鍵字,但是在C11中它們都定義在uchar.h頭文件中。 ?C++通過iostream頭文件提供寬字符I/O支持(wchar_t、char16_t和char32_t),而C99通過wchar.h頭文件提供一種完全不同的I/O支持包。 ?
11、復(fù)數(shù)類型
?C++在complex頭文件中提供一個復(fù)數(shù)類來支持復(fù)數(shù)類型。C有內(nèi)置的復(fù)數(shù)類型,并通過complex.h頭文件來支持。這兩種方法區(qū)別很大,不兼容。C更關(guān)心數(shù)值計算社區(qū)提出的需求。 ?
12、內(nèi)聯(lián)函數(shù)
?C99支持了C++的內(nèi)聯(lián)函數(shù)特性。但是,C99的實現(xiàn)更加靈活。在C++中,內(nèi)聯(lián)函數(shù)默認是內(nèi)部鏈接。在C++中,如果一個內(nèi)聯(lián)函數(shù)多次出現(xiàn)在多個文件中,該函數(shù)的定義必須相同,而且要使用相同的語言記號。例如,不允許在一個文件的定義中使用int類型形參,而在另一個文件的定義中使用int32_t類型形參。即使用typedef把int32_t定義為int也不能這樣做。但是在C中可以這樣做。C允許混合使用內(nèi)聯(lián)定義和外部定義,而C++不允許。 ?
13、C++11中沒有的C99/C11特性
?雖然在過去C或多或少可以看作是C++的子集,但是C99標準增加了一些C++沒有的新特性。下面列出了一些只有C99/C11中才有的特性: ?
?指定初始化器; ? ? ?
受限指針(Restricted pointer)?(即,restric指針); ?
?變長數(shù)組; ? ?
伸縮型數(shù)組成員;
?帶可變數(shù)量參數(shù)的宏。
審核編輯:湯梓紅
評論
查看更多