C 知識拾遺

2022-04-10 00:47:28 字數 4191 閱讀 3942

最近開始看各種「寶典」了,發現自己有好多c++死角,趕緊查漏補缺,見招拆招吧。

1、外部鏈結和內部鏈結。

在c++中,外部鏈結主要包括全域性變數(非static,非const)和非靜態自由函式(非類成員函式),類的非inline函式(包括靜態和非靜態),類的靜態資料成員(這也是為什麼類的static資料成員必須在類定義體外定義)。他們在乙個編譯單元中定義,其它編譯單元通過extern宣告訪問它們,在整個程式中這些外部鏈結的變數和函式共用相同的位址;

const,static變數和static函式,,類的定義,enum定義,union定義,inline函式定義,類的inline函式定義,typedef宣告是內部鏈結,即它們的作用域只存在於定義它們的編譯單元,在其它單元可以定義同名的變數而不會發生衝突。

這也就是為什麼在標頭檔案中可以新增const變數的定義,對非const變數卻只能用宣告。類的靜態資料成員不能再函式體內部定義,也不能在類的建構函式裡定義,就是這個道理。但是整型的const static成員可以在類定義體內部初始化,這個問題還不知道怎麼解釋。

2、命名空間使用的注意事項

命名空間可以在全域性作用域或其它作用域內部定義,但不能在函式或類內部定義。

命名空間可以在幾個部分定義,但是名字只在宣告名字的檔案中可見,這一常規限制繼續應用。

3、ptrdiff_t

用來表示兩個指向同一陣列的指標進行減法操作的型別。它在cstddef標頭檔案定義,是乙個signed整型

4、位元組對齊

位元組對齊的細節和編譯器實現相關,但一般而言,滿足三個準則:

1) 結構體變數的首位址能夠被其最寬基本型別成員的大小所整除;

2) 結構體每個成員相對於結構體首位址的偏移量(offset)都是成員大小的整數倍,如有需要編譯器會在成員之間加上填充位元組(internal adding);

3) 結構體的總大小為結構體最寬基本型別成員大小的整數倍,如有需要編譯器會在最末乙個成員之後加上填充位元組(trailing padding)。

基本型別是指前面提到的像char、short、int、float、double這樣的內建資料型別,這裡所說的「資料寬度」就是指其sizeof的大小。由於結構體的成員可以是復合型別,比如另外乙個結構體,所以在尋找最寬基本型別成員時,應當包括復合型別成員的子成員,而不是把復合成員看成是乙個整體。但在確定復合型別成員的偏移位置時則是將復合型別作為整體看待。

這裡敘述起來有點拗口,思考起來也有點撓頭,還是讓我們看看例子吧(具體數值仍以vc6為例,以後不再說明):

struct s1

char c;

int i;

}struct s3

; s1的最寬簡單成員的型別為int,s3在考慮最寬簡單型別成員時是將s1「打散」看的,所以s3的最寬簡單型別為int,這樣,通過s3定義的變數,其儲存空間首位址需要被4整除,整個sizeof(s3)的值也應該被4整除。

c1的偏移量為0,s的偏移量呢這時s是乙個整體,它作為結構體變數也滿足前面三個準則,所以其大小為8,偏移量為4,c1與s之間便需要3個填充位元組,而c2與s之間就不需要了,所以c2的偏移量為12,算上c2的大小為13,13是不能被4整除的,這樣末尾還得補上3個填充位元組。最後得到sizeof(s3)的值為16。

到這裡,朋友們應該對結構體的sizeof有了乙個全新的認識,但不要高興得太早,有乙個影響sizeof的重要參量還未被提及,那便是編譯器的pack指令。它是用來調整結構體對齊方式的,不同編譯器名稱和用法略有不同,vc6中通過#pragma pack實現,也可以直接修改/zp編譯開關。#pragma pack的基本用法為:#pragma pack( n ),n為位元組對齊數,其取值為1、2、4、8、16,預設是8,如果這個值比結構體成員的sizeof值小,那麼 該成員的偏移量應該以此值為準,即是說,結構體成員的偏移量應該取二者的最小值,

公式如下:

offsetof( item ) = min( n, sizeof( item ) )

再看示例:

#pragma pack(push) // 將當前pack設定壓棧儲存

#pragma pack(2) // 必須在結構體定義之前使用

struct s1

; struct s3

; #pragma pack(pop) // 恢復先前的pack設定

計算sizeof(s1)時,min(2, sizeof(i))的值為2,所以i的偏移量為2,加上sizeof(i)等於6,能夠被2整除,所以整個s1的大小為6。

同樣,對於sizeof(s3),s的偏移量為2,c2的偏移量為8,加上sizeof(c2)等於9,不能被2整除,新增乙個填充位元組,所以sizeof(s3)等於10。

現在,朋友們可以輕鬆的出一口氣了,:)

還有一點要注意,「空結構體」(不含資料成員)的大小不為0,而是1。試想乙個「不佔空間」的變數如何被取位址、兩個不同的「空結構體」變數又如何得以區分呢於是,「空結構體」變數也得被儲存,這樣編譯器也就只能為其分配乙個位元組的空間用於佔位了。如下:

struct s5 ;

對於類的sizeof大小,主要看它的非靜態資料成員以及是否有虛函式(無論是繼承還是自己本身有的),有虛函式則新增乙個4位元組的虛函式表指標,如果是多重繼承(n重),則應該加n*4

對於聯合體來說,只要求整個聯合體的大小是最寬資料型別的整數倍。

結構體有位域的情況下,也不要忘記滿足成員偏移量和整個結構體大小是對齊位元組整數倍這一限制

5) 整個結構體的總大小為最寬基本型別成員大小的整數倍。

5、extern "c"

#ifdef __cplusplus 

extern "c"

#endif

這段**的含義是:如果當前**是c++**,那麼加入extern "c"處理其中的**。

extern "c"的真實目的是實現類c和c++的混合程式設計。在c++原始檔中的語句前面加上extern "c",表明它按照類c的編譯和連線規約來編譯和連線,而不是c++的編譯的連線規約。這樣在類c的**中就可以呼叫c++的函式or變數等

c++**呼叫c編寫的模組,需要

extern"c"

或者extern"c"

這裡有篇講的很細緻的文章:

注:__cplusplus是c++的乙個巨集,乙個字尾名是cpp的檔案自然地定義了這個巨集。

6、#ifdef和#if defined

#ifdef name == #if defined(name)

#ifndef name == #if !defined(name)

在處理多重預定義時

#ifdef a

#ifdef b

.......

#endif

#endif 等價於

#if defined(a)&& if defined(b)

#endif

7、動態庫和靜態庫

動態庫(dynamic link library abbr,dll)技術是程式設計中經常採用的技術。其目的減少程式的大小,節省空間,提高效率,具有很高的靈活性。採用動態庫技術對於公升級軟體版本更加 容易。與靜態庫(static link library)不同,動態庫裡面的函式不是執行程式本身的一部分,而是根據執行需要按需載入,其執行**可以同時在多個程式中共享。

程式編譯一般需經預處理、編譯、彙編和鏈結幾個步驟。在我們的應用中,有一些公共**是需要反覆使用,就把這些**編譯為「庫」檔案;在鏈結步驟中,聯結器將從庫檔案取得所需的**,複製到生成的可執行檔案中。這種庫稱為靜態庫,其特點是可執行檔案中包含了庫**的乙份完整拷貝;缺點就是被多次使用就會有多份冗餘拷貝。

靜態庫和動態庫是兩種共享程式**的方式,它們的區別是:靜態庫在程式的鏈結階段被複製到了程式中,和程式執行的時候沒有關係;動態庫在鏈結階段沒有被複製到程式中,而是程式在執行時由系統動態載入到記憶體中供程式呼叫。使用動態庫的優點是系統只需載入一次動態庫,不同的程式可以得到記憶體中相同的動態庫的複本,因此節省了很多記憶體。

8、assert()巨集

#define ndebug:用來關閉assert()巨集

ndebug巨集定義必須在標頭檔案assert.h引入「之前」,才起到阻止assert巨集起作用的效果 !有些人的文章中寫到在release模式下預設定義了#define ndebug,在vs2008下測試後發現不是這樣的。也就是說,debug和release中assert巨集都會得到展開,除非手動顯式定義了#define ndebug。

debug版本會自動的定義_debug巨集,在此條件下_assert巨集才可使用,而release下_debug巨集被關閉。

asp知識拾遺

最近做的乙個小 碰到了許多問題,能解決的都解決了,還有的沒辦法就找了替代的解決辦法.下面收集一下 1 在選擇了一系列的checkbox後的提交表單提交後,會獲取到name1,逗號,空格,name2,逗號,空格,結果,系統需要獲取這些值,我用了以下 實現.uname request.form user...

css 知識拾遺

父級元素高度撐開 第二方式 推薦 doctype html html lang en head meta charset utf 8 meta name viewport content width device width,initial scale 1.0 title document titl...

入門知識拾遺

一 bytes型別 二 三元運算 result 值1 if 條件 else 值2 如果條件為真 result 值1 如果條件為假 result 值2 三 進製 計算機記憶體位址和為什麼用十六進製制?為什麼用16進製制 1 計算機硬體是0101二進位制的,16進製制剛好是2的倍數,更容易表達乙個命令或...