日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當(dāng)前位置:首頁 > 嵌入式 > 嵌入式大雜燴
[導(dǎo)讀]· ?正 ?· ?文 ?· ?來 ?· ?啦 ?· 前言 ------在上篇文章里面,我們分析了預(yù)處理的一個(gè)完整過程,這能夠讓我們理解一個(gè)寫好的程序,在生成一個(gè)可執(zhí)行文件,到底發(fā)生了什么,對(duì)我們?cè)诖笮凸こ添?xiàng)目里面有助于對(duì)程序的理解;今天我們繼續(xù)接著上篇文章的基礎(chǔ)上




·  正  ·  文  ·  來  ·  啦  ·


前言

------在上篇文章里面,我們分析了預(yù)處理的一個(gè)完整過程,這能夠讓我們理解一個(gè)寫好的程序,在生成一個(gè)可執(zhí)行文件,到底發(fā)生了什么,對(duì)我們?cè)诖笮凸こ添?xiàng)目里面有助于對(duì)程序的理解;今天我們繼續(xù)接著上篇文章的基礎(chǔ)上,來分享有關(guān)c語言里面關(guān)于宏定義的用法!


宏定義基本語法

每個(gè)#define行(即邏輯行)由三部分組成:第一部分是指令 #define 自身,“#”表示這是一條預(yù)處理命令,“define”為宏命令。第二部分為宏(macro),一般為縮略語,其名稱(宏名)一般大寫,而且不能有空格,遵循C變量命令規(guī)則。第三部分“替換文本”可以是任意常數(shù)、表達(dá)式、字符串等。在預(yù)處理工作過程中,代碼中所有出現(xiàn)的“宏名”,都會(huì)被“替換文本”替換。這個(gè)替換的過程被稱為“宏代換”或“宏展開”(macro expansion)?!昂甏鷵Q”是由預(yù)處理程序自動(dòng)完成的。在C語言中,“宏”分為兩種:無參數(shù) 和 有參數(shù)(這里有參數(shù)先不舉例子,下面具體分析的話,讀者可以詳細(xì)看到示例來理解這個(gè))。下面是宏定義的基本形式:


     #define   宏名     宏體注意:宏體后面不要加分號(hào)“;”,這個(gè)在寫代碼的時(shí)候要小心點(diǎn)哦



宏定義的優(yōu)點(diǎn)和缺點(diǎn)

------優(yōu)點(diǎn):


1、方便程序的修改:


      使用簡單宏定義可用宏代替一個(gè)在程序中經(jīng)常使用的常量,這樣在將該常量改變時(shí),不用對(duì)整個(gè)程序進(jìn)行修改,只修改宏定義的字符串即可,而且當(dāng)常量比較長時(shí), 我們可以用較短的有意義的標(biāo)識(shí)符來寫程序,這樣更方便一些(特別當(dāng)跨平臺(tái)的時(shí)候,要修改程序一些參數(shù)的時(shí)候,用宏定義的話,只需要修改宏定義的宏名就可以代表修改了整個(gè)程序里面用到這個(gè)宏名,就不用一個(gè)個(gè)去改了,極大的提升了工作效率!)。


2、提高程序的運(yùn)行效率

     

       這里我們就拿帶參宏和函數(shù)來對(duì)比了:


      (1)宏定義是在預(yù)處理期間處理的,而函數(shù)是在編譯期間處理的。這個(gè)區(qū)別帶來的實(shí)質(zhì)差異是:宏定義最終是在調(diào)用宏的地方把宏體原地展開,而函數(shù)是在調(diào)用函數(shù)處跳轉(zhuǎn)到函數(shù)中去執(zhí)行,執(zhí)行完后再跳轉(zhuǎn)回來。


注:宏定義和函數(shù)的最大差別就是:宏定義是原地展開,因此沒有調(diào)用開銷;而函數(shù)是跳轉(zhuǎn)執(zhí)行再返回,因此函數(shù)有比較大的調(diào)用開銷。所以宏定義和函數(shù)相比,優(yōu)勢(shì)就是沒有調(diào)用開銷,沒有傳參開銷,所以當(dāng)函數(shù)體很短(尤其是只有一句話時(shí))可以用宏定義來替代,這樣效率高。


     (2)帶參宏和帶參函數(shù)的一個(gè)重要差別就是:宏定義不會(huì)檢查參數(shù)的類型,返回值也不會(huì)附帶類型;而函數(shù)有明確的參數(shù)類型和返回值類型。當(dāng)我們調(diào)用函數(shù)時(shí)編譯器會(huì)幫我們做參數(shù)的靜態(tài)類型檢查,如果編譯器發(fā)現(xiàn)我們實(shí)際傳參和參數(shù)聲明不同時(shí)會(huì)報(bào)警告或錯(cuò)誤。


注:用函數(shù)的時(shí)候程序員不太用操心類型不匹配因?yàn)榫幾g器會(huì)檢查,如果不匹配編譯器會(huì)警告(但是實(shí)際測試并沒有警告,理論上是有的);用宏的時(shí)候程序員必須很注意實(shí)際傳參和宏所希望的參數(shù)類型一致,否則可能編譯不報(bào)錯(cuò)但是運(yùn)行有誤(一般所希望的是整型數(shù)據(jù)類型,不然結(jié)果一般會(huì)出錯(cuò),下面的例子就是);而且最好在宏體里面每個(gè)參數(shù)都帶小括號(hào),因?yàn)橛袝r(shí)候會(huì)涉及到運(yùn)算符號(hào)的優(yōu)先級(jí)問題,這樣一來寫程序的話就不會(huì)引起bug了。


#include <stdio.h>

#define MAX(a, b) (((a)>(b)) ? (a) : (b))

int max(int a, int b)
{
    if (a > b)
            return a;
    else
            return b;
}

int main(void)
{


    float a, b, c;
    a = 1.5;
    b = 4.7;



    c = MAX(a, b);                          // 展開后:c = (((a)>(b)) ? (a) : (b));
    printf("c = %d.\n", c);
    c = max(a, b);                          // 無法展開,只能調(diào)用
    printf("c = %d.\n", c);


    return 0;
}


我們來看一下它預(yù)處理過后成了什么樣了:

2 "b.c" 2
6 "b.c"
int max(int a, int b)
{
   if (a > b)
   return a;
   else
    return b;
}

int main(void)
{


      float a, b, c;
      a = 1.5;
      b = 4.7;



      c = (((a)>(b)) ? (a) : (b));
      printf("c = %d.\n", c);
      c = max(a, b);
      printf("c = %d.\n", c);


      return 0;
}


演示結(jié)果(你會(huì)看到):

b.c: In function ‘main’:
b.c:25:15: warning: format ‘%d’ expects argument of type 
int’, but argument 2 has type ‘double’ [-Wformat=]
 printf("c = %d.\n", c);
          ~^
          %f
 b.c:27:15: warning: format ‘%d’ expects argument of type 
int’, but argument 2 has type ‘double’ [-Wformat=]
  printf("c = %d.\n", c);
          ~^
          %f
 root@ubuntu-virtual-machine:/home/ubuntu# ./a.out
 c = -1272947832.
 c = 4.


總結(jié):宏和函數(shù)各有千秋,各有優(yōu)劣。總的來說,如果代碼比較多用函數(shù)適合而且不影響效率;但是對(duì)于那些只有一兩句話的函數(shù)開銷就太大了,適合用帶參宏。但是用帶參宏又有缺點(diǎn):不檢查參數(shù)類型。


------缺點(diǎn):


  • 由于是直接嵌入的,所以代碼可能相對(duì)多一點(diǎn)。


  • 嵌套定義過多可能會(huì)影響程序的可讀性,而且很容易出錯(cuò),不容易調(diào)試。


  • 對(duì)帶參的宏而言,由于是直接替換,并不會(huì)檢查參數(shù)是否合法,存在安全隱患。





宏定義的用法

1、嵌套宏的使用:

 #include <stdio.h>

 #define M    10  
 #define N     M
 int main(void)
 
{

   printf("the M is %d\n",M);

   printf("the N is %d\n",N);

   return 0;

 }


預(yù)處理之后:


 # 5 "b.c"
int main(void)
{

    printf("the M is %d\n",10);

    printf("the N is %d\n",10);

    return 0;

}


演示結(jié)果(簡單來講嵌套宏說白了還是直接替換的作用):

root@ubuntu-virtual-machine:/home/ubuntu# ./a.out
the M is 10
the N is 10


2、#運(yùn)算符

      出現(xiàn)在宏定義中的#運(yùn)算符把跟在其后的參數(shù)轉(zhuǎn)換成一個(gè)字符串。有時(shí)把這種用法的#稱為字符串化運(yùn)算符。例如:

#include <stdio.h>

#define  M(n)   "hhh"#n        

int main(void)
{

printf("the M(6) is %s\n",M(6));


return 0;

}


演示結(jié)果:

   the M(6is hhh6


3、##運(yùn)算符

      ##運(yùn)算符用于把參數(shù)連接到一起。預(yù)處理程序把出現(xiàn)在##兩側(cè)的參數(shù)合并成一個(gè)符號(hào)??聪旅娴睦樱?/span>

#include <stdio.h>

#define  M(a,b,c)          a##b##c

int main(void)
{

  printf("the M(2,3,4) is %d\n",M(2,3,4));
 return 0;

}


演示結(jié)果:

the M(2,3,4is 234


4、宏定義中使用了do{}  while(0) (這種形式在代碼還是經(jīng)常能看的到的,下面我還是用例子來慢慢引導(dǎo)大家來看懂這用這個(gè)的含義):

 #include <stdio.h>

 #define  M(n)  \
 printf("the n is %d\n",n);\
 printf("the M(n) is %d\n",n);


 int main(void)
 
{

   int n=8;
   int a=1;
   if(a)
           M(n);


   return 0;

}


預(yù)處理后(你可以看到這樣一來,第二條語句就沒有在我們if語句的范圍內(nèi)了,而且讀者應(yīng)該注意到,帶參宏有點(diǎn)像函數(shù)調(diào)用,調(diào)用這個(gè)也是一條語句,所以語句后面加了“;”,這里在實(shí)際編譯過程中是多加了,會(huì)導(dǎo)致編譯報(bào)錯(cuò);但是不在這條語句后面加的話,就不像一條語句了,不過它是可以編譯通過的,下面改進(jìn)后的程序就是這種情況):

 # 8 "b.c"
 int main(void)
{

     int n=8;
     int a=1;
    if(a)
      printf("the n is %d\n",n);printf("the M(n) is %d\n",n);;


   return 0;

}

改進(jìn)后(加了{(lán)}):
 #include <stdio.h>

 #define  M(n)  \
 {printf("the n is %d\n",n);\
 printf("the M(n) is %d\n",n);}


 int main(void)
 
{

    int n=8;
    int a=1;
   if(a)
          M(n);
   else
    printf("error\n");
   return 0;    
}
預(yù)處理后(這個(gè)程序就會(huì)報(bào)錯(cuò)了,就是我上面分析的原因):
 # 8 "b.c"
 int main(void)
 {

     int n=8;
     int a=1;
     if(a)
    {printf("the n is %d\n",n);printf("the M(n) is 
 %d\n"
,n);};
     else
      printf("error\n");

   return 0;

 }

演示結(jié)果:
  root@ubuntu-virtual-machine:/home/ubuntu# gcc b.c
  b.c: In function ‘main’:
  b.c:15:2: error: ‘else’ without a previous ‘if
  else
  ^~~~

最后我們來使用這個(gè)結(jié)構(gòu)再次來改進(jìn)上面的代碼看看效果如何:
 #include <stdio.h>

 #define  M(n)  \
 do{\
     printf("the n is %d\n",n);\
     printf("the M(n) is %d\n",n);\
 }while(0)


 int main(void)
{

      int n=8;
      int a=1;
      if(a)
            M(n);
      else
     printf("error\n");

      return 0;

  }

預(yù)處理后(加了do{}while(0)后,上面的問題就全部解決了):
 # 10 "b.c"
 int main(void)
 {

      int n=8;
      int a=1;
      if(a)
     do{printf("the n is %d\n",n);printf("the M(n) is 
   %d\n"
,n);}while(0);
      else
       printf("error\n");

    return 0;

 }

5、可變宏的使用:

      C99中規(guī)定宏可以像函數(shù)一樣帶有可變參數(shù),實(shí)現(xiàn)思想就是宏定義中參數(shù)列表的最后一個(gè)參數(shù)為省略號(hào)(也就是三個(gè)英文輸入法下的句號(hào))。這樣預(yù)定義宏__VA_ARGS__就可以被用在替換部分中,以表明省略號(hào)代表什么:

#include<stdio.h>
#define Variable_Macro(...)   printf(__VA_ARGS__)
int main(void)
{
     Variable_Macro("This is a variable macro test...\n");
     Variable_Macro("My age is %d",22);
     return 0;
}


預(yù)處理后:

   # 3 "b.c"
   int main(void)
  
{
      printf("This is a variable macro test...\n");
      printf("My age is %d",22);
      return 0;
  }


演示結(jié)果:

 

 This is a variable macro test...
 My age is 22


注意:帶參宏后面不能再有參數(shù),而我們的帶參函數(shù)前面必須要有參數(shù)(這里我就不舉例子關(guān)于帶參函數(shù)了)

#include<stdio.h>
#define Variable_Macro(...,a)   printf(__VA_ARGS__)
int main(void)
{
     Variable_Macro("This is a variable macro test...\n");
     Variable_Macro("My age is %d",22);
     return 0;
}


演示結(jié)果:

   

 root@ubuntu-virtual-machine:/home/ubuntu# gcc b.c
 b.c:2:27: error: missing ')' in macro parameter list
 #define Variable_Macro(...,a)   printf(__VA_ARGS__)
                       ^




總結(jié)

今天的分享就到這里了,晚安!



關(guān)注公眾號(hào),每周分享至少3篇開源技術(shù)干貨,文章中如有沒看懂的地方可以私聊我,我看到了會(huì)立馬回復(fù)你,個(gè)人微信號(hào):a18879499804

免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場,如有問題,請(qǐng)聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

LED驅(qū)動(dòng)電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: 驅(qū)動(dòng)電源

在工業(yè)自動(dòng)化蓬勃發(fā)展的當(dāng)下,工業(yè)電機(jī)作為核心動(dòng)力設(shè)備,其驅(qū)動(dòng)電源的性能直接關(guān)系到整個(gè)系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動(dòng)勢(shì)抑制與過流保護(hù)是驅(qū)動(dòng)電源設(shè)計(jì)中至關(guān)重要的兩個(gè)環(huán)節(jié),集成化方案的設(shè)計(jì)成為提升電機(jī)驅(qū)動(dòng)性能的關(guān)鍵。

關(guān)鍵字: 工業(yè)電機(jī) 驅(qū)動(dòng)電源

LED 驅(qū)動(dòng)電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個(gè)照明設(shè)備的使用壽命。然而,在實(shí)際應(yīng)用中,LED 驅(qū)動(dòng)電源易損壞的問題卻十分常見,不僅增加了維護(hù)成本,還影響了用戶體驗(yàn)。要解決這一問題,需從設(shè)計(jì)、生...

關(guān)鍵字: 驅(qū)動(dòng)電源 照明系統(tǒng) 散熱

根據(jù)LED驅(qū)動(dòng)電源的公式,電感內(nèi)電流波動(dòng)大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關(guān)鍵字: LED 設(shè)計(jì) 驅(qū)動(dòng)電源

電動(dòng)汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產(chǎn)業(yè)的重要發(fā)展方向。電動(dòng)汽車的核心技術(shù)之一是電機(jī)驅(qū)動(dòng)控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機(jī)驅(qū)動(dòng)系統(tǒng)中的關(guān)鍵元件,其性能直接影響到電動(dòng)汽車的動(dòng)力性能和...

關(guān)鍵字: 電動(dòng)汽車 新能源 驅(qū)動(dòng)電源

在現(xiàn)代城市建設(shè)中,街道及停車場照明作為基礎(chǔ)設(shè)施的重要組成部分,其質(zhì)量和效率直接關(guān)系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進(jìn)步,高亮度白光發(fā)光二極管(LED)因其獨(dú)特的優(yōu)勢(shì)逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關(guān)鍵字: 發(fā)光二極管 驅(qū)動(dòng)電源 LED

LED通用照明設(shè)計(jì)工程師會(huì)遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

關(guān)鍵字: LED 驅(qū)動(dòng)電源 功率因數(shù)校正

在LED照明技術(shù)日益普及的今天,LED驅(qū)動(dòng)電源的電磁干擾(EMI)問題成為了一個(gè)不可忽視的挑戰(zhàn)。電磁干擾不僅會(huì)影響LED燈具的正常工作,還可能對(duì)周圍電子設(shè)備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來解決L...

關(guān)鍵字: LED照明技術(shù) 電磁干擾 驅(qū)動(dòng)電源

開關(guān)電源具有效率高的特性,而且開關(guān)電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機(jī)重量也有所下降,所以,現(xiàn)在的LED驅(qū)動(dòng)電源

關(guān)鍵字: LED 驅(qū)動(dòng)電源 開關(guān)電源

LED驅(qū)動(dòng)電源是把電源供應(yīng)轉(zhuǎn)換為特定的電壓電流以驅(qū)動(dòng)LED發(fā)光的電壓轉(zhuǎn)換器,通常情況下:LED驅(qū)動(dòng)電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: LED 隧道燈 驅(qū)動(dòng)電源
關(guān)閉