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

C語言深入講解宏的定義與使用方法

 更新時間:2022年04月19日 11:42:15   作者:清風(fēng)自在 流水潺潺  
在 C 語言中,可以采用命令 #define 來定義宏。該命令允許把一個名稱指定成任何所需的文本,例如一個常量值或者一條語句。在定義了宏之后,無論宏名稱出現(xiàn)在源代碼的何處,預(yù)處理器都會把它用定義時指定的文本替換掉

一、C語言中的宏定義

  • #define是預(yù)處理器處理的單元實體之一
  • #define 定義的宏可以出現(xiàn)在程序的任意位置
  • #define 定義之后的代碼都可以使用這個宏
  • #define 定義的宏常量可以直接使用
  • #define 定義的宏常量本質(zhì)為字面量

下面的宏常量定義正確嗎?

編寫代碼來測試:

#define ERROR -1
#define PATH1 "D:\test\test.c"
#define PATH2 D:\test\test.c
#define PATH3 D:\test\
test.c
 
int main()
{
    int err = ERROR;
    char* p1 = PATH1;
    char* p2 = PATH2;
    char* p3 = PATH3;
}

先使用gcc -E Test.c -o Test.i 進(jìn)行預(yù)編譯,預(yù)編譯沒有報錯,結(jié)果如下:

# 1 "Test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "Test.c"
 
int main()
{
    int err = -1;
    char* p1 = "D:\test\test.c";
    char* p2 = D:\test\test.c;
    char* p3 = D:\testtest.c;
}

直接進(jìn)行編譯,發(fā)現(xiàn) char* p2 = PATH2; char* p3 = PATH3; 報錯

這說明宏定義是正確的,但是編譯是過不了的,只是

#define PATH2 D:\test\test.c

#define PATH3 D:\test\

不符合語法規(guī)范。

二、宏定義表達(dá)式

  • #define 表達(dá)式的使用類似函數(shù)調(diào)用
  • #define 表達(dá)式可以比函數(shù)更強(qiáng)大
  • #define 表達(dá)式比函數(shù)更容易出錯

強(qiáng)大之處其中之一就是可以求數(shù)組的大小,這是不能編寫函數(shù)辦到的。

下面看一段宏表達(dá)式的代碼:

#include <stdio.h>
 
#define _SUM_(a, b) (a) + (b)
#define _MIN_(a, b) ((a) < (b) ? (a) : (b))
#define _DIM_(a) sizeof(a)/sizeof(*a)
 
int main()
{
    int a = 1;
    int b = 2;
    int c[4] = {0};
 
    int s1 = _SUM_(a, b);
    int s2 = _SUM_(a, b) * _SUM_(a, b);
    int m = _MIN_(a++, b);
    int d = _DIM_(c);
 
    printf("s1 = %d\n", s1);
    printf("s2 = %d\n", s2);
    printf("m = %d\n", m);
    printf("d = %d\n", d);
 
    return 0;
}
 

下面為輸出結(jié)果,但是 s2 我們預(yù)期的結(jié)果應(yīng)該是 9,m 的值我們預(yù)期的結(jié)果應(yīng)該是 1,這是怎么回事呢?

下面進(jìn)行預(yù)編譯看看代碼到底是怎么運行的,輸入 gcc -E Test.c -o Test.i

int main()
{
    int a = 1;
    int b = 2;
    int c[4] = {0};
 
    int s1 = (a) + (b);
    int s2 = (a) + (b) * (a) + (b);
    int m = ((a++) < (b) ? (a++) : (b));
    int d = sizeof(c)/sizeof(*c);
 
    printf("s1 = %d\n", s1);
    printf("s2 = %d\n", s2);
    printf("m = %d\n", m);
    printf("d = %d\n", d);
 
    return 0;
}

通過上面宏定義的替換,我們很容易知道為什么結(jié)果跟我們想的不一樣。

三、宏表達(dá)式與函數(shù)的對比

  • 宏表達(dá)式被預(yù)處理器處理,編譯器不知道宏表達(dá)式的存在
  • 宏表達(dá)式用“實參”完全替代形參,不進(jìn)行任何運算
  • 宏表達(dá)式?jīng)]有任何的“調(diào)用”開銷
  • 宏表達(dá)式中不能出現(xiàn)遞歸定義

所以,下面遞歸定義就是錯誤的:

四、有趣的問題

宏定義的常量或表達(dá)式是否有作用域限制?(沒有)

下面看一個宏作用域分析的代碼:

#include <stdio.h>
 
void def()
{
    #define PI 3.1415926
    #define AREA(r) r * r * PI
}
 
double area(double r)
{
    return AREA(r);
}
 
int main()
{
    double r = area(5);
 
    printf("PI = %f\n", PI);
    printf("d = 5; a = %f\n", r);
    
    return 0;
}

下面為輸出結(jié)果:

作用域的概念是針對 C 語言中的變量和函數(shù),不針對宏。宏表達(dá)式被預(yù)處理器處理,編譯器不知道宏表達(dá)式的存在。

五、強(qiáng)大的內(nèi)置宏

含義示例
_FILE_被編譯的文件名file1.c
_LINE_當(dāng)前行號25
_DATE_編譯時的日期Jan 31 2021
_TIME_編譯時的時間17:01:01
_STDC_編譯器是否遵循標(biāo)準(zhǔn)C規(guī)范1

下面看一個宏使用的綜合示例:

#include <stdio.h>
#include <malloc.h>
 
#define MALLOC(type, x) (type*)malloc(sizeof(type)*x)
 
#define FREE(p) (free(p), p=NULL)
 
#define LOG(s) printf("[%s] {%s:%d} %s \n", __DATE__, __FILE__, __LINE__, s)
 
#define FOREACH(i, m) for(i=0; i<m; i++)
#define BEGIN {
#define END   }
 
int main()
{
    int x = 0;
    int* p = MALLOC(int, 5);
    
    LOG("Begin to run main code...");
    
    FOREACH(x, 5)
    BEGIN
        p[x] = x;
    END
    
    FOREACH(x, 5)
    BEGIN
        printf("%d\n", p[x]);
    END
    
    FREE(p);
    
    LOG("End");
    
    return 0;
}

下面為輸出結(jié)果:

可以看到宏定義是很強(qiáng)大的,可以打印出日期,文件名,行號,不使用宏定義很難實現(xiàn)。

六、小結(jié)

  • 預(yù)處理器直接對宏進(jìn)行文本替換
  • 宏使用時的參數(shù)不會進(jìn)行求值和運算
  • 預(yù)處理器不會對宏定義進(jìn)行語法檢查
  • 宏定義時出現(xiàn)的語法錯誤只能被編譯器檢測
  • 宏定義的效率高于函數(shù)調(diào)用
  • 宏的使用會帶來一定的副作用

到此這篇關(guān)于C語言深入講解宏的定義與使用方法的文章就介紹到這了,更多相關(guān)C語言 宏的定義內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++實現(xiàn)浮點數(shù)精確加法

    C++實現(xiàn)浮點數(shù)精確加法

    這篇文章主要為大家詳細(xì)介紹了C++實現(xiàn)浮點數(shù)精確加法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-05-05
  • C語言如何利用異或進(jìn)行兩個值的交換詳解

    C語言如何利用異或進(jìn)行兩個值的交換詳解

    最近在工作中遇到了兩個值交換的需求,發(fā)現(xiàn)自己對異或有些忘記,所以索性寫出來,方便以后需要的時候參考學(xué)習(xí),下面這篇文章主要給大家介紹了關(guān)于C語言如何利用異或進(jìn)行兩個值的交換的相關(guān)資料,需要的朋友可以參考下。
    2017-09-09
  • 從頭學(xué)習(xí)C語言之二維數(shù)組

    從頭學(xué)習(xí)C語言之二維數(shù)組

    這篇文章主要為大家詳細(xì)介紹了C語言之二維數(shù)組,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-01-01
  • 關(guān)于C++中虛擬繼承的一些總結(jié)分析

    關(guān)于C++中虛擬繼承的一些總結(jié)分析

    虛擬繼承在一般的應(yīng)用中很少用到,所以也往往被忽視,這也主要是因為在C++中,多重繼承是不推薦的,也并不常用
    2013-09-09
  • 簡單舉例說明C++中break和continue語句的用法

    簡單舉例說明C++中break和continue語句的用法

    這篇文章主要介紹了簡單舉例說明C++中break和continue語句的用法,是C++入門學(xué)習(xí)中的基礎(chǔ)只是,需要的朋友可以參考下
    2015-09-09
  • 淺談const變量賦值報錯分析

    淺談const變量賦值報錯分析

    在類中 只有靜態(tài)變量能賦值 如果你不賦值 編譯器會認(rèn)為你這個變量根本沒用 不能被修改 又沒有初始值 兩個辦法 在構(gòu)造函數(shù)的初始化列表賦值 或者在const前面加一個static
    2015-07-07
  • C語言實現(xiàn)學(xué)生選課系統(tǒng)

    C語言實現(xiàn)學(xué)生選課系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C語言實現(xiàn)學(xué)生選課系統(tǒng),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-02-02
  • C語言棧之順序棧

    C語言棧之順序棧

    這篇文章主要為大家詳細(xì)介紹了C語言的順序棧,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • C++ 多態(tài)性虛函數(shù)和動態(tài)綁定學(xué)習(xí)筆記

    C++ 多態(tài)性虛函數(shù)和動態(tài)綁定學(xué)習(xí)筆記

    這篇文章主要為大家介紹了C++ 多態(tài)性虛函數(shù)和動態(tài)綁定學(xué)習(xí)筆記,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • return和break的區(qū)別解析

    return和break的區(qū)別解析

    這篇文章主要介紹了return和break的區(qū)別解析,需要的朋友可以參考下
    2014-02-02

最新評論

邵阳县| 武强县| 汝州市| 年辖:市辖区| 邢台市| 建昌县| 临夏市| 东丽区| 浦县| 原阳县| 天峻县| 定远县| 凤冈县| 故城县| 历史| 合肥市| 仙桃市| 思茅市| 清原| 安吉县| 肥城市| 丹江口市| 信丰县| 延津县| 锡林郭勒盟| 巴马| 和顺县| 凭祥市| 武胜县| 江口县| 太原市| 平南县| 靖边县| 太保市| 怀集县| 海门市| 疏附县| 田阳县| 怀宁县| 囊谦县| 舟山市|