科銳課堂筆記 2017 3 13 巨集與預處理指令

2021-07-28 11:48:46 字數 1630 閱讀 2849

基本功只能花時間自己練,別人代勞不得。

全域性變數必須匯出符號,靜態全域性是檔案作用域(私有)所以不匯出符號,注在彙編中全域性變數不修飾預設指static靜態全域性(顯示宣告public才會匯出符號)。靜態區域性由於使用名稱粉碎機制就算匯出符號別的函式也用不了(檢查名字不匹配)。extern 「c」宣告使用c風格的名稱粉碎。

使用巨集相當於編譯器幫你自動化完成查詢替換的功能,而且巨集更具有靈活性,一則可以定義帶引數的巨集,二來巨集是不會替換字串裡的內容的。(引號內)

巨集定義格式:

無參巨集:#define 巨集名 內容(可空)

巨集名一般名稱全大寫,以區分函式。當內容為空此時定義了乙個說明巨集,說明巨集可用來當注釋資訊看或配合預處理指令改變程式內容流程。

有參巨集:#define 巨集名(參1,參2,…) 表示式

比如定義乙個取兩者最大值的max巨集,#define max(a,b) (((a)>(b)) ? (a):(b))。使用有參巨集需要注意的是,因為巨集最終都會展開替換到原始碼中,所以在表示式內引用的引數必須要用括號括起來,不但引數,連整個表示式,當中區域性的表示式都要使用括號,不用括號的話遇到運算子優先順序會破壞執行流程,得不到預想中的結果。

兩個#號連線巨集,末尾加\續行。編譯選項表示預編譯巨集,在所有原始檔的任何部分都能訪問到。

使用巨集解決vc6 for內變數作用域bug的例子:

c++規定for內定義的變數屬於塊作用域,而在vc6中屬於函式作用域,在同乙個函式裡使用兩次for(int i=……)會報重定義錯誤,這裡可以定義乙個巨集解決該問題,請看下面:

#define for if(1)for

#define for if(0){}else for

是不是問題已經完美解決了,這裡使用巨集統一了for的作用域(限制在if塊內),這樣無論vc6還是高版本都可以無差異編譯通過了。再補充幾點,後一種巨集定義的想法是基於, if(0)是個不可達分支可去掉優化,if(1)是必達分支作者怕編譯器作者優化水平不行,多出幾行判斷**。其實微軟vc系列作者水平都很高,無論必達或不可達分支都不會產生實際的**(/o2編譯選項)。

使用巨集實現模板函式的例子:

#define define_sum(type) type sum_##type(type a,type b)

#define call_sum(type,a,b) sum_##type(a,b)

在檔案頭部定義幾個型別,如:

define_sum(int)

define_sum(float)

然後使用call_sum(int,3,5)呼叫int版,call_sum(float,6.1,7.2)呼叫float版。c++的模板函式就**於此。

預處理指令(編譯前處理):

#號開頭的關鍵字都是預處理指令,/p編譯選項可檢視.i檔案,裡面已經是巨集展開和預處理處理後的內容。

幾個預編譯指令:

#if #else #endif

#ifdef #else #endif

#ifndef #else #endif

#undef取消定義

#pragma once只編譯一次(多用於標頭檔案)

科銳課堂筆記 2017 4 7 函式過載與類

c 支援函式過載,函式過載指具有相同的函式名,但引數不同 型別 個數或順序 並且這些過載函式都在同一作用域裡。實現的原理還是使用名稱粉碎機制,c 的名稱粉碎更為複雜點,將函式作用域 每個引數型別都加在內部名字中,這些碎粉化後的名字可以通過vc tools的undname工具翻譯成可讀名,如果在函式定...

科銳課堂筆記 2017 2 28 迴圈相關

大數階乘演算法優化,例求10的階乘1 2 3 4 5 6 7 8 9 10可轉換成 1 3 5 7 9 2 4 6 8 10 1 3 5 7 9 1 2 3 4 5 2,即把乙個大數階乘轉換成若干小數階乘,乘多少次2可用左移指令完成,其中2 5可去掉,記住有多少次2 5結果末位就加上多少個0,這樣一...

科銳課堂筆記 2017 3 17 結構體

結構體是不同資料 包括型別或邏輯意義 的集合。在設計定義乙個結構體時,要把其合理的資料組織在一塊。點 運算子用來訪問結構體成員,點運算子優先順序僅次於括號。vc6中預設的編譯選項,結構體成員對齊為8位元組 zp8 結構體成員的偏移位址規則是,必須是結構體成員對齊位元組數 zp?和該成員型別長度 字串...