⑴ C關於宏的計算
宏在預編譯的時候處理,包含#的指令,都是在預編譯的時候處理
相對於運行階段,你也可以認為是編譯階段。
它只是簡單的字元串替換,不是計算。
它不影響代碼的執行速度,但是可能會增加代碼的長度,影響最終生成的可執行文件的大小。
補充:
表達式(10/5)的計算,應該在運行的時候吧
無法通過編譯選項控制這個的。
⑵ 在C類語言(C/C++/OC)中經常會用到宏,請問宏在編譯期、連接期還是運行期起作用具體發生了什麼
宏最主要是預處理時候用的,剩下的編譯的時候處理的,某些可能會影響到鏈接。具體發生什麼得看具體什麼指令了。
⑶ 宏是什麼意思啊,起到什麼作用啊
宏,就是「文本替換」,是在編譯預處理階段,宏根據一系列預定義的規則替換一定的文本模式。
以一樓朋友舉的例子而言,在預處理期,編譯器將你的程序代碼里所有出現「MAX」的地方,全都替換成「100」,但是,引號里的內容不換,例如:
printf("MAX");
這句里的MAX不會被替換,它執行的效果是在屏幕上列印出「MAX」三個字母而不是「100」。
for(int i=0; i<MAX; i++)
{
……
}
這裡面,「i<MAX」會替換成「i<100」
另外,宏還可以用來簡化一些復雜的操作,甚至是帶有參數,例如,在視頻游戲和動畫製作過程中,我們使用大量24位的點陣圖,但我們的顯卡往往對24位定址支持不夠好,都使用32位定址模式,那麼我們就要給點陣圖里的每一像素,添加8位ALPHA值,湊成32位,為和顯卡配合融洽。
我們習慣使用這樣的宏:
#define RGB32BIT(a,r,g,b) ((b)+((g)<<8)+((r)<<16)+((a)<<24))
你會覺得這跟函數有些類似,的確如此,但是,它們很大的區別就是:(帶參數)的函數擁有類型檢查,而(帶參數)的宏沒有,就像我上面舉的例子,你必須確保a,r,g,b都是正整數,否則就會出錯,而使用函數則可以在編譯階段檢查出類型錯誤。不過卻要有時間和內存上的開銷,而宏沒有;所以各有利弊吧!
⑷ const、define、static、extern
extern用於變數的聲明,告訴編譯器:已經存在一個全局變數,但是不在當前的編譯單元內,需要連接的時候在其他編譯單元中尋找。
修改變數作用域為當前編譯單元,變數生命周期不變;
避免重復定義全局變數
2.2. 修飾局部變數 -
修改變數的生命周期為整個工程周期,變數作用域不變
const修飾右邊的變數,用來限制變數為只讀屬性。
在程序的預編譯階段進行替換處理。
區別:
1.define宏是在預處理階段展開。
const常量是編譯運行階段使用。
2.define不做檢查,不會報編譯錯誤,只是替換。const會編譯檢查,會報編譯錯誤
3.define在展開的時候才分配內存,展開幾次分配幾次內存。const在定義的時候會分配一次內存到靜態區,使用時不重復分配
4.define可以定義一些簡單的運算函數
聲明一個只讀的靜態變數
在多個文件中經常使用的同一個全局變數。
使用場景:
1、.h文件中聲明
2、.m文件中賦值
3、pch文件中導入頭文件即可在整個項目中訪問
這里直接訪問即可,都不用放到.pch文件中,因為默認許可權是internal
public : 最大許可權,可以在當前framework和其他framwork中訪問;
internal : 默認許可權,可以在當前framework中隨意訪問;
private : 私有許可權,只能在當前文件中訪問;
一般常量的話,都用extern const 來代替define。
因為一旦定義#define的方式,整個工程將被重新編譯,這樣帶來的時間浪費可想而知
當然了很多情況還是代替不了的,一般定義常量的時候是應該使用這種方式來定義,不過也只是常量宏不被推薦,但是類函數宏用的還是很方便的,
const、#define的優缺點
編譯器可以對const進行類型安全檢查。而對#define只進行字元替換,沒有類型安全檢查,並且在字元替換可能會產生意料不到的錯誤。
這種情況還可能出現以下錯誤
Sending 'const NSString *__strong' to parameter of type 'NSString *' discards qualifiers
原因是需要 NSString* 的地方使用了 const NSString*
.h中 extern const NSString* 替換為 extern NSString* const
.m中 const NSString* 替換為 NSString* const
解釋:前者相當於指針本身不可修改,後者表示指針指向的內容不可修改,兩者的作用都是使字元串只可讀不可寫。
⑸ C語言編譯系統對宏替換的處理是在什麼時候進行的
是正式工作開始之前的准備工作,所以宏替換是在對程序編譯之前進行的。
宏替換是C/C++的預處理中的一部分,對於宏定義中的形參,在替換列表中,如果不是作為#或##的操作數,那麼將對應實參完全展開(相當於對實參進行求值),然後將替換列表中的形參替換掉,如果是#或##的操作數。
(5)宏處理是在整個編譯的哪個階段擴展閱讀:
宏的用途在於自動化頻繁使用的序列或者是獲得一種更強大的抽象能力。
計算機語言如C語言或匯編語言有簡單的宏系統,由編譯器或匯編器的預處理器實現。C語言的宏預處理器的工作只是簡單的文本搜索和替換,使用附加的文本處理語言如M4,C程序員可以獲得更精巧的宏。
宏的行為如同是函數對自身程序文本的變形,並且可以應用全部語言來表達這種變形。一個C宏可以定義一段語法的替換,然而一個Lisp的宏卻可以控制一節代碼的計算。
⑹ C語言文件的編譯與執行的四個階段並分別描述
開發C程序有四個步驟:編輯、編譯、連接和運行。
任何一個體系結構處理器上都可以使用C語言程序,只要該體系結構處理器有相應的C語言編譯器和庫,那麼C源代碼就可以編譯並連接到目標二進制文件上運行。
1、預處理:導入源程序並保存(C文件)。
2、編譯:將源程序轉換為目標文件(Obj文件)。
3、鏈接:將目標文件生成為可執行文件(EXE文件)。
4、運行:執行,獲取運行結果的EXE文件。
(6)宏處理是在整個編譯的哪個階段擴展閱讀:
將C語言代碼分為程序的幾個階段:
1、首先,源代碼文件測試。以及相關的頭文件,比如stdio。H、由預處理器CPP預處理為.I文件。預編譯的。文件不包含任何宏定義,因為所有宏都已展開,並且包含的文件已插入。我歸檔。
2、編譯過程是對預處理文件進行詞法分析、語法分析、語義分析和優化,生成相應的匯編代碼文件。這個過程往往是整個程序的核心部分,也是最復雜的部分之一。
3、匯編程序不直接輸出可執行文件,而是輸出目標文件。匯編程序可以調用LD來生成可以運行的可執行程序。也就是說,您需要鏈接大量的文件才能獲得「a.out」,即最終的可執行文件。
4、在鏈接過程中,需要重新調整其他目標文件中定義的函數調用指令,而其他目標文件中定義的變數也存在同樣的問題。
⑺ C語言的編譯過程
C編譯的整個過程很復雜,大致可以分為以下四個階段:
預處理階段在該階段主要完成對源代碼的預處理工作,主要包括對宏定義指令,頭文件包含指令,預定義指令和特殊字元的處理,如對宏定義的替換以及文件頭中所包含的文件中預定義代碼的替換等,總之這步主要完成一些替換工作,輸出是同源文件含義相同但內容不同的文件。
編譯、優化階段編譯就是將第一階段處理得到的文件通過詞法語法分析等轉換為匯編語言。優化包括對中間代碼的優化,如刪除公共表達式,循環優化等;和對目標代碼的生成進行的優化,如如何充分利用機器的寄存器存放有關變數的值,以減少內存訪問次數。
匯編階段將匯編語言翻譯成機器指令。
鏈接階段鏈接階段的主要工作是將有關的目標文件連接起來,即將在一個文件中引用的符號同該符號在另外一個文件中的定義連接起來,使得所有的目標文件成為一個能夠被操作系統裝入執行的統一整體。
⑻ C語言enum成員與宏定義作用域的區別
與作用域無關,宏是預編譯階段,在代碼中做字元替換,而enum是編譯階段。
整個編譯過程是先處理宏,再處理enum類型。
這樣寫有一個考慮,比如:
#ifdef PTHREAD_PROCESS_PRIVATE
int i=PTHREAD_PROCESS_PRIVATE;
#else
int i=100;
#endif
看出來好處了嗎?在不同的開發環境下,只要記得一個名字就可以給變數賦enum成員值,不需要記住二個。
比如下面要記2個詞彙aaa和bbb,多不方便,看代碼的人又不便理解:
enum{
aaa
#define bbb
}
#ifdef bbb
int i=aaa;
#else
#endif
總結一下:
宏控制不同環境下代碼編譯,但要用到enum,又要方便使用不用記太多東西,這就是為什麼這個代碼要這樣寫,是很高明的做法。
⑼ C語言預處理編譯鏈接各個階段錯誤,分階段的說一下
預處理階段主要是處理宏指令,像什麼#include指令、#define指令還有條件編譯指令等。
編譯階段主要是檢查C語言程序的語法錯誤,即編寫的代碼是否符合C語言規則,編譯是以.c源文件為單位編譯成.obj文件(或者是.o文件)。
鏈接階段,就是把相關的.obj文件、所需的庫文件等組合成一個可執行的文件。如果缺少相關所需文件,就會鏈接報錯。
指針異常,數組下標越界這些錯誤屬於語義錯誤,這個只能在執行的時候才能發現問題,這些也叫運行時錯誤。
⑽ C語言取消宏定義
宏定義屬於預編譯階段的處理過程。預編譯是整個編譯過程的第一步。編譯器將檢查代碼中的所有預編譯語句,遇到#include則將被包含的文件整個復制粘貼到#include位置替換#include語句,遇到#define語句則定義該宏並將文本中所有出現該宏的代碼予以替換,遇到#ifdef、#ifndef、#endif語句則進行判斷和執行相應操作。這個時候程序的源代碼還是文本形式,編譯器還沒有開始語法分析,連函數的概念都不存在,又怎麼判斷函數的代碼誰先執行誰後執行呢?