C語(yǔ)言程序的編譯與預(yù)處理基礎(chǔ)定義講解
程序的翻譯環(huán)境和執(zhí)行環(huán)境
在ANSIC的任何一種實(shí)現(xiàn)中,存在兩個(gè)不同的環(huán)境:翻譯環(huán)境和執(zhí)行環(huán)境
翻譯環(huán)境:源代碼被轉(zhuǎn)換為可執(zhí)行的機(jī)器指令。
執(zhí)行環(huán)境:實(shí)際執(zhí)行代碼。
1.翻譯環(huán)境
- 組成一個(gè)程序的每個(gè)源文件通過(guò)編譯分別轉(zhuǎn)換成目標(biāo)文件(object code)。
- 每個(gè)目標(biāo)文件由鏈接器(linker)捆綁在一起,形成一個(gè)單一而完整的可執(zhí)行程序。
- 鏈接器同時(shí)也會(huì)引入標(biāo)準(zhǔn)C函數(shù)庫(kù)中任何被該程序所用到的函數(shù),而且它可以搜索程序員個(gè)人的程序庫(kù),將齊需要的函數(shù)也鏈接到程序中。
2.運(yùn)行環(huán)境
程序的執(zhí)行環(huán)境:
1.程序必須載入內(nèi)存中。在有操作系統(tǒng)的環(huán)境中:一般這個(gè)由操作系統(tǒng)完成。在獨(dú)立的環(huán)境中,程序的載入必須由手工安排,也可能是通過(guò)可執(zhí)行代碼置入只讀內(nèi)存來(lái)完成。
2.程序的執(zhí)行便開(kāi)始。接著便調(diào)用main函數(shù)。
3.開(kāi)始執(zhí)行程序代碼。這個(gè)時(shí)候程序?qū)⑹褂靡粋€(gè)運(yùn)行時(shí)堆棧(stack),存儲(chǔ)函數(shù)的局部變量和返回地址。程序同時(shí)也可以使用靜態(tài)(static)內(nèi)存,存儲(chǔ)于靜態(tài)內(nèi)存中的變量在程序的整個(gè)執(zhí)行過(guò)程中一種保留它們的值。
4.終止程序。正常終止main函數(shù),也有可能是意外終止。
預(yù)處理詳解
預(yù)定義符號(hào)
#define
#define 定義標(biāo)識(shí)符
語(yǔ)法:
#define name stuff
#define MAX 100 #define REG register //為register創(chuàng)建一個(gè)簡(jiǎn)短的名字 #define do_forever for(;;) //用符號(hào)來(lái)替換一種實(shí)現(xiàn) #define PRINT printf("file:%s\tline:%d\tdate:%s\time:%s\n", \ __FILE__,__LINE__,__DATE__,__TIME__) //如果定義的stuff過(guò)長(zhǎng),可以分成幾行來(lái)寫(xiě),除了最后一行外,每行的后面都加一個(gè)反斜杠(續(xù)行符)。
在define定義標(biāo)識(shí)符的時(shí)候,最后不要加(;)號(hào)。
#define定義宏
#define機(jī)制包括了一個(gè)規(guī)定,允許把參數(shù)替換到文本中,這種實(shí)現(xiàn)通常稱(chēng)為宏(macro)或定義宏(define macro)。
宏的聲明方式:
#define name ( parament - list ) stuff
其中的parament - list 是一個(gè)由逗號(hào)隔開(kāi)的符號(hào)表,它們可能出現(xiàn)在stuff中。
參數(shù)列表的左括號(hào)必須與name緊緊相鄰。若兩者之間存在空白,參數(shù)列表就會(huì)被解釋為stuff的一部分。
#define SQUARE( x ) x * x
#define替換規(guī)則
1.在調(diào)用宏時(shí),首先對(duì)參數(shù)進(jìn)行檢查,看看是否包含任何由#define定義的符號(hào)。如果是,它們將首先被替換。
2.替換文本隨后被插入到程序中原來(lái)文本的位置。對(duì)于宏,參數(shù)名被它們的值替換。
3.最后,再一次對(duì)結(jié)果文件進(jìn)行掃描,看看是否還包含任何由#define定義的符號(hào)。如果是,就重復(fù)上述的過(guò)程。
注意:
1.宏參數(shù)和#define定義中可以出現(xiàn)其它#define定義的變量。但是對(duì)于宏,不能出現(xiàn)遞歸。
2.當(dāng)預(yù)處理器搜索#define定義的符號(hào)的時(shí)候,字符串常量的內(nèi)容并不被搜索。
#和##
如何把參數(shù)插入到字符串中?
#include<stdio.h> #define PRINT(n) printf("the value of "#n" is %d\n",n) int main() { int a = 7; PRINT(a); int b = 5; PRINT(b); return 0; }
##的作用:
帶副作用的宏參數(shù)
當(dāng)宏參數(shù)在宏的定義中出現(xiàn)超過(guò)一次的時(shí)候,如果參數(shù)帶有副作用,那么在使用這個(gè)宏的時(shí)候就可能會(huì)出現(xiàn)危險(xiǎn),導(dǎo)致不可預(yù)知的后果。副作用就是表達(dá)式求值的時(shí)候出現(xiàn)的永久性效果。
x+1;//不帶有副作用 x++;//帶有副作用
舉一個(gè)例子:
宏和函數(shù)對(duì)比
宏通常被應(yīng)用于執(zhí)行簡(jiǎn)單的運(yùn)算。例如在找出兩個(gè)數(shù)中的較大一個(gè)。
#define MAX(a, b) ((a)>(b)?(a):(b))
為什么不用函數(shù)來(lái)完成這個(gè)任務(wù)呢?有其下原因:
1.用于調(diào)用函數(shù)和從函數(shù)返回的代碼可能比實(shí)際執(zhí)行這個(gè)小型計(jì)算工作所需要的時(shí)間更多。所以宏比函數(shù)在程序的規(guī)模和速度方面更勝一籌。
2.函數(shù)的參數(shù)必須聲明為特定的類(lèi)型。所以函數(shù)只能在類(lèi)型合適的表達(dá)式上使用。而這個(gè)宏可以適用于整形、長(zhǎng)整型、浮點(diǎn)型等類(lèi)型。宏是類(lèi)型無(wú)關(guān)的。
宏和函數(shù)的對(duì)比:
命名約定
一般來(lái)講函數(shù)和宏的使用語(yǔ)法非常相似。所以語(yǔ)法本身沒(méi)有辦法幫我們區(qū)分二者。
所以一般是:把宏名全部大寫(xiě),函數(shù)名不要全部大寫(xiě)。
#undef
這條指令用于移除一個(gè)宏定義。
#undef NAME //如果現(xiàn)存的一個(gè)名字需要被重定義,那么它的舊名字首先要被移除
例如:
命令行定義
許多C的編譯器提供了一種功能,允許程序在命令行中定義符號(hào)。用于啟動(dòng)編譯過(guò)程。
例如:當(dāng)我們根據(jù)同一個(gè)源文件要編譯出不同的一個(gè)程序的不同版本的時(shí)候,這個(gè)特性就比較有用。(若某個(gè)程序中聲明了一個(gè)某長(zhǎng)度的數(shù)組,若機(jī)器內(nèi)存有限,我們需要一個(gè)很小的數(shù)組,若機(jī)器內(nèi)存大一些,我們就需要一個(gè)大一點(diǎn)的數(shù)組)。
條件編譯
在編譯一個(gè)程序的時(shí)候如果要將一條語(yǔ)句或者一組語(yǔ)句編譯或者放棄是很方便的??梢杂脳l件編譯指令。
常見(jiàn)的條件編譯指令:
文件包含
#include指令可以使另外一個(gè)文件被編譯。
這種替換的方式:預(yù)處理先刪除這條指令,并用包含文件的內(nèi)容替換。這樣一個(gè)源文件被包含幾次,那就實(shí)際被編譯幾次。
頭文件被包含的方式:
通常一個(gè)大型的項(xiàng)目會(huì)調(diào)用多個(gè)程序合并,那么如何避免頭文件的重復(fù)包含而提高效率呢?
常見(jiàn)的有一下兩種解決方法:
1.每個(gè)頭文件的開(kāi)頭寫(xiě):
#ifndef __TEST_H__ #define __TEST_H__ //頭文件的內(nèi)容 #endif
2.定義頭文件之前包含這一句話:
#pragma once
到此這篇關(guān)于C語(yǔ)言程序的編譯與預(yù)處理基礎(chǔ)定義講解的文章就介紹到這了,更多相關(guān)C語(yǔ)言編譯與預(yù)處理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MFC實(shí)現(xiàn)對(duì)話框編輯控件上拖拽文件
這篇文章主要為大家詳細(xì)介紹了MFC實(shí)現(xiàn)對(duì)話框編輯控件上拖拽文件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-06-06C++實(shí)現(xiàn)日期類(lèi)(Date類(lèi))的方法
下面小編就為大家?guī)?lái)一篇C++實(shí)現(xiàn)日期類(lèi)(Date類(lèi))的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-01-01C語(yǔ)言實(shí)現(xiàn)貪吃蛇游戲(單人版)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)貪吃蛇游戲單人版,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-06-06解析C/C++指針、函數(shù)、結(jié)構(gòu)體、共用體
這篇文章主要介紹了C/C++指針、函數(shù)、結(jié)構(gòu)體、共用體的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-01-01C++與Java分別解決活動(dòng)選擇問(wèn)題和帶權(quán)活動(dòng)選擇問(wèn)題
這篇文章介紹了C++與Java分別解決活動(dòng)選擇問(wèn)題和帶權(quán)活動(dòng)選擇問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06c++ Protobuf解決數(shù)據(jù)傳輸瓶頸面試精講
這篇文章主要介紹了c++ Protobuf解決數(shù)據(jù)傳輸瓶頸利器面試精講,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10