溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

C++/C語言深度剖析(1)

發(fā)布時間:2020-06-06 23:44:50 來源:網(wǎng)絡(luò) 閱讀:451 作者:hbxu 欄目:移動開發(fā)

C/C++語言其實剛學(xué)起來難度不大,學(xué)著學(xué)著就發(fā)現(xiàn)這也不對那也不對。碰上高手的代碼,有時候都看不懂。一大堆的宏定義,一大堆的指針,一連串的繼承、重載、多態(tài)覆蓋。看得頭昏腦脹。實在是非常痛苦。再加上如果開發(fā)MFC/ATL程序,這些程序是MS在WINAPI上的封裝,通過VISUAL STUDIO工具一陣自動生成。最后你發(fā)現(xiàn),C/C++在哪都不知道,你只知道某個API,某個類了。語言不見了。出現(xiàn)這種情況,有些人說好,說明你已經(jīng)達到一個境界了。可是你自己會清楚,C/C++,這個語言,你究竟在哪?別人讓你舉幾個C/C++基本特征,心中也說不清楚。看到C/C++語言寫的代碼,你也是心里似懂不懂的,有時候,心里想,何必究根呢?只要程序運行沒錯就行。真要程序Coredump了,再去GDB調(diào)試吧。我相信工作中的人想法80%都是這樣想的。沒有多少人愿意花時間去深究C/C++的內(nèi)部機制的。一個因為時間不允許,工作任務(wù)緊,另一個確實來說,參考資料也很少。這里C++/C語言深度剖析,是自己的一個學(xué)習(xí)記錄。那么首先從C/C++源碼開始說起。

【1】版本和功能聲明,說到這里,不得不提編程規(guī)范,也就是通常意義意上的Code specific。這里所說的編程規(guī)范,我相信幾乎每家公司都有,可是一拿到代碼庫上的代碼一看,還是亂七八糟的。這不能怪Review的人,也不能怪寫Code的人。首先我們要理解,寫程序和管程序的都是人。人都是彈性,不像機器,設(shè)定一個規(guī)則,就一定按照這個規(guī)則執(zhí)行。人是這個世界上最奇怪的一種機器,他是不按常理出牌的。因此,要嚴(yán)格的要求一個人去遵守某種規(guī)則基本上是不可能的。那為什么還是每家公司都搞這些寫在墻上沒人看的規(guī)范,干嘛呢?也許是領(lǐng)導(dǎo)自我安慰,也許是QA部門的一種成績。反正我理解寫在紙上的規(guī)范通常都不是規(guī)范。只有落實到行動中的才是規(guī)范。那么我這里提規(guī)范干嘛呢?那我這里寫這個規(guī)范是從解決自己的痛苦來說。我們通常很痛苦的就是拿到別人代碼,一個目錄,不知道從哪看起,不停的找main函數(shù)。找到main函數(shù)然后一個一個的找來找去,猜來猜去。顯然一個清晰的目錄結(jié)構(gòu)對別人對自己都是一種享受。C/C++中有一個默認(rèn)的命名規(guī)則就是  頭文件 include目錄  源碼文件 src目錄或者source目錄。庫文件 lib目錄.編譯后執(zhí)行文件 bin目錄。第二個痛苦的就是拿到一個CPP文件中,函數(shù)一大堆,不知道干嘛?那么必要的簡短注釋通常是非常有用的。那這里有一個問題,就是你說這注釋是寫在頭文件中好還是源文件中好呢?這也是一個糾結(jié)的問題?兩邊都寫就顯得傻,寫哪一邊比較好呢?我們知道不管是SVN、git還是Clearcase它都是以文件作為管理單位的。因此,對每個文件來說,都是公司或個人的私有財產(chǎn)。因此,從這點來說,每個文件都需要進行版本聲明、作者聲明。那么功能說明從某種意義上說還是以頭文件為主。通常來說頭文件說明主要功能。源文件中說明實現(xiàn)細節(jié)。下面是一個推薦范本。

C++/C語言深度剖析(1)

這個范本實際也是比較死的。實際上有些公司是CR/SR號來標(biāo)識版本修改記錄的。下面是一個參考例子。

C++/C語言深度剖析(1)

【2】預(yù)處理寫法。我們知道編譯器在預(yù)處理過程中通常都是針對#開頭的符號進行簡單替換處理。這里有三個問題,我們分別解決。

1)第一個問題,就是同一個源碼文件,如果包含頭文件過程,出現(xiàn)重復(fù)。應(yīng)該怎么處理。從語法上來說有時候肯定沒錯,當(dāng)然有時候也會出現(xiàn)錯誤,因為相同的代碼拷貝了兩份。但是從生成文件的效率來說,肯定不好。如下所示:

file1.h 含有extern int size

file2.h 含有#include “file1.h” f

ile3.h 含有#include “file1.h”

這時如果file.c含有 #include “file2.h” 和#include “file3.h”。 這時經(jīng)過預(yù)處理編譯生成的file.i中就會含有兩個extern int size。造成聲明失敗。因此,我們這可以采用如下兩種解決方法:一種是使用ifndef/define/endif,

#ifndef FILE1

#define FILE1 “file1.h”

#include FILE1

#endif

另一種是使用#pragma once。這一種在VC中比較常見,但是不是所有編譯器支持。它是針對單個文件在物理上只被編譯一次,如果相同的文件有多份拷貝,也就是說內(nèi)容相同,但文件名不一樣。這種方法是行不通的。所以最好的方法還是第一種。因此,在寫C++頭文件時,一般在開頭都要如下進行聲明。

C++/C語言深度剖析(1)

2)第二問題就是include 關(guān)于系統(tǒng)路徑頭文件和當(dāng)前用戶定義路徑搜索的寫法,我們都知道其中系統(tǒng)路徑用#include<file.h>,用戶路徑用#include “file.h”。當(dāng)然這里在編譯時,我們是需要不管是GCC還VC的CL都是需要指定-I參數(shù)路徑。VC是在IDE中進行配置。GCC是通過-I參數(shù)設(shè)置。但是通常我們開發(fā)時C++對標(biāo)準(zhǔn)庫寫法的建議是#<iostream>,這又是為什么呢?我們知道C++與C不同,有幾點是C完全沒有的:命名空間和.hpp尾的頭文件。首先講第一點,可能最容易接受的就是可移植性,C++新標(biāo)準(zhǔn)為了不受.h的牽制,并且實際上它也不建議了。就使用不帶后綴的系統(tǒng)庫。第二點,接著前面來說,你沒有后綴,那編譯器到底搜索的是哪個文件呢?這一點是有點讓人接受不了,但實際上標(biāo)準(zhǔn)并沒有明確區(qū)分,比喻說,<iostream>和<iostream.h>,前者可以肯定的是在命名空間std中,并且支持寬符,std標(biāo)準(zhǔn)組件中搜索到就不一定是iostream.h文件,并且里面的函數(shù)都是有命名空間的,也不是全局函數(shù)??赡芸吹竭@里更迷惑了。這還要從C++引入命名空間講起。理論上講引入命名空間導(dǎo)致了C++不再有絕對意義上的全局函數(shù),也就避免了大規(guī)模開發(fā)時需要避免全局變量和全局函數(shù)同名的問題。因此,C++標(biāo)準(zhǔn)庫都是建立在std命名空間范圍內(nèi)。但是我們知道C都是全局函數(shù),C++是C的超集。如何兼容C的函數(shù)呢?C++使用了一個蠢辦法,就是同名重寫到std空間中去,比喻說iostream對應(yīng)就是iostream.h。但是為了避免混淆,使用std命名空間的,就不帶h。

3)第三個問題也比較重要,就是C和C++代碼混合編譯時,該如何處理。我相信大部分C++程序中都或多或少中含有純C的代碼,C++因為一些特性與C不完全兼容,因此,混和編譯C++和C程序時時候會產(chǎn)生一些問題,具體什么問題呢?我們以函數(shù)來做比較,比喻函數(shù)void foo(int x,int y)在C++編譯器生成時是_foo_int_int函數(shù)名,而在C中因為沒有重載特性,所以生成的函數(shù)名是_foo,這時如果在編譯時恰好這個函數(shù)是在C庫中,那么用C++生成的這個函數(shù)就無法在鏈接時查到正確的C庫。同理反過來也是這樣,如果一段C程序使用到C++生成的函數(shù),也會出現(xiàn)同樣的問題,因此,處理這此問題就需要如下使用extern “C”來定義頭文件。

C++/C語言深度剖析(1)

另一個問題是如果C中使用C++生成的函數(shù),怎么使用呢?顯然C中是不能使用extern “C”標(biāo)識的。那么該如何處理呢?可以在C++中聲明這個函數(shù)為extern “C”,但在C中使用extern來引用。

C++/C語言深度剖析(1)

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI