最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語言預(yù)處理預(yù)編譯命令及宏定義詳解

 更新時(shí)間:2021年10月13日 17:15:10   作者:Bitdancing  
這篇文章主要為大家介紹了C語言預(yù)處理預(yù)編譯命令及宏定義的詳解,其中包含運(yùn)行環(huán)境命名約定條件及#under等基礎(chǔ)詳解,有需要的朋友可以借鑒參考下

.c 源程序 ----- 編譯 ----- 鏈接 ---- exe ----運(yùn)行 -------->

程序翻譯環(huán)境和執(zhí)行環(huán)境

翻譯環(huán)境:源代碼被轉(zhuǎn)換為可執(zhí)行機(jī)器指令(二進(jìn)制代碼)。

執(zhí)行環(huán)境:用于實(shí)際執(zhí)行代碼。

翻譯環(huán)境:詳解編譯+鏈接

在這里插入圖片描述

1.組成程序的每個(gè)源文件通過編譯過程分別轉(zhuǎn)換成目標(biāo)代碼。

2.每個(gè)目標(biāo)文件由鏈接器捆綁在一起,形成一個(gè)單一而完整的可執(zhí)行程序。

3.鏈接器同時(shí)也會(huì)引入標(biāo)準(zhǔn)C函數(shù)庫中任何被該程序所用到的函數(shù),而且他可以搜索程序員個(gè)人的程序庫,將其需要的函數(shù)也鏈接到程序。

extern聲明外部文件中的函數(shù)

在這里插入圖片描述

1. 編譯 — 預(yù)處理/預(yù)編譯 test.c ---- test.i

文本操作

#include 頭文件的包含

注釋刪除:使用空格替換注釋

#define 替換,所以宏無法進(jìn)行調(diào)試。

……

2. 編譯 — 編譯 test.i ---- test.s

把c語言代碼翻譯成匯編代碼

語法分析

詞法分析

語義分析

符號(hào)匯總

3. 編譯 — 匯編 test.s ---- test.obj

把匯編代碼轉(zhuǎn)換成二進(jìn)制代碼(指令)。

形成符號(hào)表。(符號(hào)+地址)

4. 鏈接 test.obj ---- test.exe

合并段表

符號(hào)表的合并和重定位

在這里插入圖片描述

運(yùn)行環(huán)境

1.程序必須載入內(nèi)存中。在有操作系統(tǒng)的環(huán)境中:一般這個(gè)由操作系統(tǒng)完成。在獨(dú)立的環(huán)境中,程序的載入必須由手工安排,也可能是通過可執(zhí)行代碼置入只讀內(nèi)存來完成。

2.程序的執(zhí)行便開始。接著便調(diào)用main函數(shù)。

3.開始執(zhí)行程序代碼。這個(gè)時(shí)候程序?qū)⑹褂靡粋€(gè)運(yùn)行時(shí)堆棧(stack),存儲(chǔ)函數(shù)的局部變量和返回地址。程序同時(shí)也可以使用靜態(tài)(static)內(nèi)存,存儲(chǔ)于靜態(tài)內(nèi)存中的變量在程序的整個(gè)執(zhí)行過程一直保留他們的值。

4.終止程序。正常終止main函數(shù);也有可能是意外終止

預(yù)處理/預(yù)編譯詳解

預(yù)定義符號(hào)

本來就有的符號(hào)

__FILE__      //進(jìn)行編譯的源文件
__LINE__     //文件當(dāng)前的行號(hào)
__DATE__    //文件被編譯的日期
__TIME__    //文件被編譯的時(shí)間
__STDC__    //如果編譯器遵循ANSI C,其值為1,否則未定義

應(yīng)用

printf("data: %s\n time: %s" ,__DATE__,__TIME__);

輸出

data: Jul 13 2021
time: 15:13:54

#define 定義標(biāo)識(shí)符

宏和define區(qū)別,宏是有參數(shù)的。

下面是宏的聲明方式:

#define name( parament-list ) stuff

其中的 parament-list 是一個(gè)由逗號(hào)隔開的符號(hào)表,它們可能出現(xiàn)在stuff中

參數(shù)列表的左括號(hào)必須與name緊鄰。如果兩者之間有任何空白存在,參數(shù)列表就會(huì)被解釋為stuf的一部分。

例如

#define SQUARE(X) (X)*(X)
int main()
{
    int ret = SQUARE(5);
	return 0;
}

宏的參數(shù)是替換的,不是傳參的。

在定義宏的時(shí)候不要吝嗇括號(hào)。

#和##

#的作用

使用#,把一個(gè)宏參數(shù)變成對(duì)應(yīng)的字符串。

把參數(shù)插入到字符串中

#define PRINT(X) printf("the value of "#X" is %d\n", X)
int main()
{
	int a = 10;
	int b = 20;
	PRINT(a);
	PRINT(b);
	return 0;
}

輸出

the value of a is 10
the value of b is 20

##的作用

## 可以把位于他兩邊的符號(hào)合成一個(gè)符號(hào),允許宏定義從分離的文本片段創(chuàng)建創(chuàng)建標(biāo)識(shí)符。

#define CAT(X,Y) X##Y
int main()
{
	int class84 = 2021;
	printf("%d\n", CAT(class, 84));
}

輸出

2021

帶副作用的宏參數(shù)

#define MAX(a, b)  ( (a) > (b) ? (a) : (b) )
...
x = 5;
y = 8;
z = MAX(x++, y++);
printf("x=%d y=%d z=%d\n", x, y, z);
//輸出的結(jié)果是什么?

這里我們得知道預(yù)處理器處理之后的結(jié)果是什么:

z = ( (x++) > (y++) ? (x++) : (y++));

輸出結(jié)果

x=6 y=10 z=9

宏和函數(shù)的對(duì)比

對(duì)于上述的宏,也可以用函數(shù)實(shí)現(xiàn)其功能。

使用宏的優(yōu)點(diǎn):

1.用于調(diào)用函數(shù)和從函數(shù)返回的代碼可能比實(shí)際執(zhí)行這個(gè)小型計(jì)算工作需要的時(shí)間更多,所以宏比函數(shù)在程序的規(guī)模和速度方面更勝一籌。

2.函數(shù)的參數(shù)必須聲明為特定的類型,所以函數(shù)只能在類型合適的表達(dá)式上使用。反之,這個(gè)宏可以用于整型、長(zhǎng)整型、浮點(diǎn)數(shù)等等,宏是類型無關(guān)的。

使用宏的缺點(diǎn):

1.每次調(diào)用宏,一份宏定義的代碼插入程序中,除非宏比較短,否則可能會(huì)大幅度增加代碼的長(zhǎng)度。

2.宏無法調(diào)試。在預(yù)編譯(預(yù)處理)階段,已經(jīng)把 # define 給替換了,已經(jīng)不再是宏了。

3.宏由于類型無關(guān),也就不夠嚴(yán)謹(jǐn)。

3.宏可能會(huì)帶來運(yùn)算符優(yōu)先級(jí)的問題,更容易導(dǎo)致程序出錯(cuò)。

inline 內(nèi)聯(lián)函數(shù)

命名約定

函數(shù)和宏語法相似,語言本身沒法幫我們區(qū)分二者。把宏名全部大寫,函數(shù)名不要全部大寫。

#undef 移除宏定義

這條指令用于移除宏定義。

如果現(xiàn)存的一個(gè)名字需要被重新定義,那么他的舊名字首先要被移除。

#undef NAME

命令行定義

許多C的編譯器提供了一種能力,允許在命令行中定義符號(hào),用于在啟動(dòng)編譯過程。例如:當(dāng)我們根據(jù)一個(gè)源文件要編譯出不同的一個(gè)程序的不同版本的時(shí)候,這個(gè)特性有點(diǎn)用處。假設(shè)某個(gè)程序中聲明了一個(gè)某個(gè)長(zhǎng)度的數(shù)組,如果機(jī)器內(nèi)存有限,我們需要一個(gè)很小的數(shù)組,但是另外一個(gè)機(jī)器內(nèi)存大寫,我們需要一個(gè)數(shù)組能夠大寫。

條件編譯

在這里插入圖片描述

#define DEBUG
#ifdef DEBUG
#endif

常見的條件編譯指令

#if 常量表達(dá)式
//...
#endif

舉例子:為真參與編譯,為假 (0)不參與編譯。

#if 1
	printf("balabala....");
#endif

二、多個(gè)分支的條件編譯

#if 常量表達(dá)式
//...
#elif 常量表達(dá)式
//...
#else
//....
#endif

舉例子

#if 1==1
#elif 2==1
#else
#endif

三、判斷是否被定義

#if defined(symbol)
#ifdef symbol
#if !defined(symbol)
#ifndef symbol

四、嵌套指令

#if defined(OS_UNIX)
	#ifdef OPTION1  
			unix_version_option1();
	#endif
	#ifdef OPTION2 
			unix_version_option2();
	#endif
#elif defined(OS_MSDOS)
	#ifdef OPTION2 
			msdos_version_option2();
	#endif
#endif

文件包含

我們已經(jīng)知道,#include指令可以使另外一個(gè)文件被編譯。就像它實(shí)際出現(xiàn)于#include指令的地方一樣。這種替換的方式很簡(jiǎn)單:預(yù)處理器先刪除這條指令,并用包含文件的內(nèi)容替換。這樣一個(gè)源文件被包含10次,那就實(shí)際被編譯10次。

頭文件包含的方式:

1.本地文件包含:#include "Filename"

查找策略:先在源文件所在目錄下查找,如果該頭文件未找到,編譯器就像查找?guī)旌瘮?shù)頭文件一樣在標(biāo)準(zhǔn)位置查找頭文件。如果找不到就提示編譯錯(cuò)誤。

2.庫文件包含:#include <Filename.h>

查找策略:查找頭文件直接去標(biāo)準(zhǔn)路徑下去查找,如果找不到就返回錯(cuò)誤信息。

這樣是不是可以說,對(duì)于庫文件也可以使用“”的形式包含?

答案是肯定的,可以。但是這樣做查找的效率就低些,當(dāng)然這樣也不容易區(qū)分是庫文件還是本地文件了。

wwww想到自己經(jīng)常重復(fù)包含,留下了悔恨的淚水~~

出現(xiàn)嵌套文件包含解決方法 :條件編譯

每個(gè)頭文件開頭這樣寫:

#ifndef __TEST__H__
#define __TEST__H__
 //頭文件的內(nèi)容
#endif         //__TEST__H__

或者

#pragma once

就可以避免頭文件的重復(fù)引入。

總結(jié)一下:預(yù)處理階段的預(yù)處理指令:條件編譯指令 / #include / #define / #error /#pragma / ……

offsetof(宏類型,成員名字)偏移量模擬實(shí)現(xiàn)

在這里插入圖片描述

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
struct S
{
	char c1;
	int a;
	char c2;
};
#define OFFSETOF(struct_name, member_name) (int)&(((struct_name*)0)->member_name)
int main()
{
	printf("%d\n", OFFSETOF(struct S, c1));
	printf("%d\n", OFFSETOF(struct S, a));
	printf("%d\n", OFFSETOF(struct S, c2));
	return 0;
}

以上就是C語言預(yù)處理預(yù)編譯命令及宏定義詳解的詳細(xì)內(nèi)容,更多關(guān)于C語言預(yù)處理預(yù)編譯命令及宏的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C++設(shè)計(jì)模式之抽象工廠模式

    C++設(shè)計(jì)模式之抽象工廠模式

    這篇文章主要介紹了C++設(shè)計(jì)模式之抽象工廠模式,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • 類成員函數(shù)的重載、覆蓋與隱藏之間的區(qū)別總結(jié)

    類成員函數(shù)的重載、覆蓋與隱藏之間的區(qū)別總結(jié)

    以下是對(duì)類成員函數(shù)的重載、覆蓋與隱藏之間的區(qū)別進(jìn)行了詳細(xì)的總結(jié)分析,需要的朋友可以過來參考下。希望對(duì)大家有所幫助
    2013-10-10
  • 深度理解C語言中的關(guān)鍵字static

    深度理解C語言中的關(guān)鍵字static

    在C語言中static主要定義全局靜態(tài)變量、定義局部靜態(tài)變量、定義靜態(tài)函數(shù),下面這篇文章主要給大家介紹了關(guān)于C語言中關(guān)鍵字static的相關(guān)資料,需要的朋友可以參考下
    2021-08-08
  • C++詳細(xì)講解常用math函數(shù)的用法

    C++詳細(xì)講解常用math函數(shù)的用法

    C++提供了很多實(shí)用的數(shù)學(xué)函數(shù),如果要使用先添加頭文件,當(dāng)然,加頭文件誰都知道,接下來我們一起詳細(xì)看看各個(gè)math函數(shù)的實(shí)際使用
    2022-04-04
  • Cocos2d-x學(xué)習(xí)筆記之CCScene、CCLayer、CCSprite的默認(rèn)坐標(biāo)和默認(rèn)錨點(diǎn)實(shí)驗(yàn)

    Cocos2d-x學(xué)習(xí)筆記之CCScene、CCLayer、CCSprite的默認(rèn)坐標(biāo)和默認(rèn)錨點(diǎn)實(shí)驗(yàn)

    這篇文章主要介紹了Cocos2d-x學(xué)習(xí)筆記之CCScene、CCLayer、CCSprite的默認(rèn)坐標(biāo)和默認(rèn)錨點(diǎn)實(shí)驗(yàn),這是一個(gè)非常值得研究的問題,需要的朋友可以參考下
    2014-09-09
  • 深入探討:linux中遍歷文件夾下的所有文件

    深入探討:linux中遍歷文件夾下的所有文件

    本篇文章是對(duì)linux中遍歷文件夾下的所有文件進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C語言實(shí)現(xiàn)電子郵件地址驗(yàn)證程序

    C語言實(shí)現(xiàn)電子郵件地址驗(yàn)證程序

    這篇文章主要介紹了C語言實(shí)現(xiàn)電子郵件地址驗(yàn)證程序,利用的是POSIX正則表達(dá)式,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2015-11-11
  • 利用Matlab復(fù)刻掃雷小游戲

    利用Matlab復(fù)刻掃雷小游戲

    windows自帶的游戲《掃雷》是陪伴了無數(shù)人的經(jīng)典游戲,本程序參考《掃雷》的規(guī)則進(jìn)行了簡(jiǎn)化,用Matlab實(shí)現(xiàn),感興趣的小伙伴可以學(xué)習(xí)一下
    2022-03-03
  • 圖文詳解C語言位運(yùn)算基礎(chǔ)知識(shí)

    圖文詳解C語言位運(yùn)算基礎(chǔ)知識(shí)

    這篇文章主要以圖文結(jié)合的方式為大家詳細(xì)介紹了C語言位運(yùn)算基礎(chǔ)知識(shí),感興趣的小伙伴們可以參考一下
    2016-07-07
  • c++詳細(xì)講解構(gòu)造函數(shù)的拷貝流程

    c++詳細(xì)講解構(gòu)造函數(shù)的拷貝流程

    拷貝構(gòu)造函數(shù)是一種特殊的構(gòu)造函數(shù),它在創(chuàng)建對(duì)象時(shí),是使用同一類中之前創(chuàng)建的對(duì)象來初始化新創(chuàng)建的對(duì)象。拷貝構(gòu)造函數(shù)通常用于:通過使用另一個(gè)同類型的對(duì)象來初始化新創(chuàng)建的對(duì)象。?復(fù)制對(duì)象把它作為參數(shù)傳遞給函數(shù)。復(fù)制對(duì)象,并從函數(shù)返回這個(gè)對(duì)象
    2022-05-05

最新評(píng)論

福海县| 威远县| 静海县| 天长市| 佛山市| 稻城县| 密山市| 甘南县| 琼海市| 连南| 饶平县| 蛟河市| 芜湖市| 福州市| 杭州市| 句容市| 河曲县| 余姚市| 沭阳县| 探索| 密山市| 曲沃县| 武夷山市| 武隆县| 噶尔县| 京山县| 韶山市| 慈利县| 清镇市| 莱阳市| 牙克石市| 娱乐| 永城市| 固始县| 彭水| 股票| 温泉县| 灌云县| 汶川县| 宁武县| 宁津县|