国产毛片a精品毛-国产毛片黄片-国产毛片久久国产-国产毛片久久精品-青娱乐极品在线-青娱乐精品

C語(yǔ)言的那些小秘密之預(yù)處理

發(fā)布時(shí)間:2016-1-29 10:24    發(fā)布者:designapp
關(guān)鍵詞: C語(yǔ)言 , 預(yù)處理
  預(yù)處理是C語(yǔ)言的一個(gè)重要知識(shí)點(diǎn),它能改善程序設(shè)計(jì)的環(huán)境,有助于編寫易移植、易調(diào)試的程序。因此,我們有必要掌握好預(yù)處理命令,在自己編程的時(shí)候靈活的使用它,使得編寫的程序結(jié)構(gòu)優(yōu)良,更加易于調(diào)試和閱讀。接下來(lái)我盡可能的把預(yù)處理中重要知識(shí)點(diǎn)向讀者講解清楚,使讀者能夠在自己以后編程的過(guò)程中熟練的使用預(yù)處理命令。
  C語(yǔ)言的預(yù)處理主要有三個(gè)方面:
  1、文件的包含
  2、宏定義
  3、條件編譯
  一、文件包含的形式有下面兩種
  1、#include "文件名"
  2、#include
  它們之間的區(qū)別在于:系統(tǒng)到頭文件目錄查找文件, "文件名"則先在當(dāng)前目錄查找,如果沒有才到頭文件目錄查找;當(dāng)然我們也可以使用在命令行來(lái)指定頭文件路徑方法。還要注意就是如果在源文件包含的頭文件之間出現(xiàn)調(diào)用的情況,那么被調(diào)用的頭文件要出現(xiàn)在調(diào)用頭文件的前面。
  二、宏定義
  宏定義的使用有兩種形式,一種不帶參數(shù),而另外一種帶參數(shù)。
  1、不帶參數(shù)
  格式: #define 標(biāo)識(shí)符 字符串
  相信上面這個(gè)格式大家并不陌生,下面還是來(lái)看看如何使用吧。當(dāng)然在講解之前我們的看看使用過(guò)程中的如下幾個(gè)注意要點(diǎn):
  (1)預(yù)處理不做語(yǔ)法檢查,所以我們選用的時(shí)候要尤其小心
  (2)宏定義寫在函數(shù)的花括號(hào)外邊,作用域?yàn)槠浜蟮某绦,通常在文件開頭部分,直到用#undef命令終止宏定義的作用域
  (3)不要在字符串中使用宏,如果宏名出現(xiàn)在字符串中那么將按照字符串進(jìn)行處理
  下面來(lái)看段代碼的使用。
  [html] view plaincopy#include
  #define N 9
  int main ()
  {
  int i,a[N];
  for(i=0;i
  {
  a[ i]=i;
  printf("%d\t",a[ i]);
  if((i+1)%3==0)
  printf("\n");
  }
  //#undef N
  printf("%d\n",N);
  }
  運(yùn)行結(jié)果為:
  [html] view plaincopy0 1 2
  3 4 5
  6 7 8
  9
  Press any key to continue
  我們?cè)诖酥饕墙榻B下宏的作用域問(wèn)題,當(dāng)在以上代碼中注釋掉#undef N時(shí),接下來(lái)的打印語(yǔ)句能夠正常的打印出;但是當(dāng)我們沒有注釋掉#undef N的時(shí)候就會(huì)出現(xiàn)error C2065: 'N' : undeclared identifier錯(cuò)誤,提示N沒有定義。接下來(lái)看看帶參數(shù)的宏的使用。
  2、帶參數(shù)
  #define 宏名(參數(shù)表) 字符串
  注意要點(diǎn):
  (1)宏名和參數(shù)的括號(hào)間不能有空格
  (2)宏替換只作替換,不做計(jì)算,不做表達(dá)式求解,這點(diǎn)要尤其注意
  (3)函數(shù)調(diào)用在編譯后程序運(yùn)行時(shí)進(jìn)行,并且分配內(nèi)存。宏替換在編譯前進(jìn)行,不分配內(nèi)存
  (4)宏的啞實(shí)結(jié)合(所謂的啞實(shí)結(jié)合類似于函數(shù)調(diào)用過(guò)程中實(shí)參替代形參的過(guò)程)不存在類型,也沒有類型轉(zhuǎn)換。
  (5)宏展開使源程序變長(zhǎng),函數(shù)調(diào)用不會(huì)
  下面來(lái)看看linux下一個(gè)典型的應(yīng)用:
  #define min(x,y) ({ typeof(x) _x = (x); typeof(y) _y = (y); (void) (&_x == &_y); _x  _y ? _x : _y; })
  在上面的兩個(gè)宏中我們發(fā)現(xiàn)有這么一句代碼(void) (&_x == &_y);可能不少讀者有點(diǎn)發(fā)懵的感覺,這啥意思呢?!其實(shí)我們細(xì)細(xì)分析就知道,首先看看“==”,這是一個(gè)邏輯表達(dá)式,它要求兩邊的比較類型必須一致,如果我們的&x和&y類型不一致,如一個(gè)為char*,另一個(gè)為int*,不是同一個(gè)類型,當(dāng)我們使用gcc編譯的時(shí)候就會(huì)出現(xiàn)警告信息,vc6則會(huì)報(bào)錯(cuò)error C2446: '==' : no conversion from 'char *' to 'int *'。這句代碼(void) (&_x == &_y); 在此的功能就相當(dāng)于執(zhí)行一個(gè)簡(jiǎn)單的判斷操作,我們用來(lái)判斷x和y的類型是否一致。別小看了這句代碼,如果學(xué)會(huì)了使用它會(huì)給你的代碼帶來(lái)不少的便捷。下面給出一個(gè)小小的事例:
  [cpp] view plaincopy#include
  void print()
  {
  printf("hello world!!!\n");
  return ;
  }
  void main(int argc,char*argv)
  {
  print();
  return ;
  }
  運(yùn)行結(jié)果為:
  


  [cpp] view plaincopyhello world!!!
  Press any key to continue
  現(xiàn)在我們來(lái)修改下代碼后看看運(yùn)行結(jié)果:
  [cpp] view plaincopy#include
  void print()
  {
  printf("hello world!!!\n");
  return ;
  }
  void main(int argc,char*argv)
  {
  #define print() ((void)(3))
  print();
  return ;
  }
  運(yùn)行結(jié)果為:
  [cpp] view plaincopyPress any key to continue
  這兒的結(jié)果沒有了我們之前的那句hello world!!!,可以看出這個(gè)時(shí)候函數(shù)并沒有被調(diào)用,這是因?yàn)槲覀兪褂昧?define print() ((void)(3)),使得之后調(diào)用函數(shù)print()轉(zhuǎn)換為了一個(gè)空操作,所以這個(gè)函數(shù)在接下來(lái)的代碼中都不會(huì)被調(diào)用了,就像被“沖刷掉”了一樣?吹竭@兒你是不是想起我們之前的那篇《C語(yǔ)言的那些小秘密之?dāng)嘌浴妨四,我們同樣可以使用這種方法來(lái)實(shí)現(xiàn)斷言的關(guān)閉,方法與之類似,在此就不再講解了,有興趣的讀者可以自己試試。講到這兒似乎應(yīng)該結(jié)束了,但是細(xì)心的讀者會(huì)有另外一個(gè)疑惑?在#define min(x,y) ({ typeof(x) _x = (x); typeof(y) _y = (y); (void) (&_x == &_y); _x
  #define print(...) printf(__VA_ARGS__)
  int main(int argc,char*argv)
  {
  print("hello world----%d\n",1111);
  return 0;
  }
  運(yùn)行結(jié)果為:
  [cpp] view plaincopyroot@ubuntu:/home/shiyan# ./arg
  hello world----1111
  接著往下看。
  #define printf (tem, ...) fprintf (stdout, tem, ## __VA_ARGS__)
  如有對(duì)fprintf不熟悉的讀者可以自己查查函數(shù)手冊(cè),在此不再講解。
  [cpp] view plaincopy#include
  #define print(temp, ...) fprintf(stdout, temp, ##__VA_ARGS__)
  int main(int argc,char*argv)
  {
  print("hello world----%d\n",1111);
  return 0;
  }
  運(yùn)行結(jié)果為:
  [cpp] view plaincopyroot@ubuntu:/home/shiyan# ./arg
  hello world----1111
  temp在此的作用為設(shè)定輸出字符串的格式,后邊“...”為可變參數(shù),F(xiàn)在問(wèn)題來(lái)了,我們?cè)诤甓x中為什么要使用“##”呢?如果我們沒有使用##會(huì)怎么樣呢?看看下面的代碼:
  [cpp] view plaincopy#include
  #define print(temp, ...) fprintf(stdout, temp, __VA_ARGS__)
  int main(int argc,char*argv)
  {
  print("hello world\n");
  return 0;
  }
  編譯時(shí)發(fā)生了如下錯(cuò)誤:
  [cpp] view plaincopyroot@ubuntu:/home/shiyan# gcc arg.c -o arg
  arg.c: In function ‘main’:
  arg.c:7:2: error: expected expression before ‘)’ token
  為什么會(huì)出現(xiàn)上面的錯(cuò)誤呢,現(xiàn)在我們來(lái)分析下,我們進(jìn)行下宏替換,print("hello world\n")就變?yōu)榱薴printf(stdout, "hello world\n",)這樣我們就發(fā)現(xiàn)了后面出現(xiàn)了一個(gè)逗號(hào),所以導(dǎo)致了錯(cuò)誤,如果有“##”就不會(huì)出現(xiàn)這樣的錯(cuò)誤了,這是因?yàn)槿绻勺儏?shù)被忽略或?yàn)榭盏臅r(shí)候,“##”操作將使預(yù)處理器去除掉它前面的那個(gè)逗號(hào)。如果存在可變參數(shù)時(shí)候,它也能正常工作。講了“##”,我們當(dāng)然也要講講“#”。先來(lái)看看下面一段代碼:
  [cpp] view plaincopy#include
  #define return_exam(p) if(!(p)) \
  {printf("error: "#p" file_name:%s\tfunction_name:%s\tline:%d .\n",\
  __FILE__, __func__, __LINE__); return 0;}
  int print()
  {
  return_exam(0);
  }
  int main(int argc,char*argv)
  {
  print();
  printf("hello world!!!\n");
  return 0;
  }
  運(yùn)行結(jié)果為:
  [cpp] view plaincopyroot@ubuntu:/home/shiyan# ./arg
  error: 0 file_name:arg.c function_name:print line:9 .
  hello world!!!
  我們發(fā)現(xiàn)在運(yùn)行結(jié)果中打印出了出錯(cuò)的文件名、函數(shù)名、以及行號(hào)。采用宏定義來(lái)檢測(cè)函數(shù)的返回值是否正確,僅僅是為了體現(xiàn)出我們要講解的宏,所以代碼做了最大的簡(jiǎn)化工作,讀者在自己編寫代碼時(shí)候要學(xué)會(huì)這樣的檢測(cè)方式。“#”的作用就是將其后面的宏參數(shù)進(jìn)行字符串化操作,就是在宏變量進(jìn)行替換之后在其左右各加上一個(gè)上雙引號(hào),這就使得"#p"變味了""p""我們發(fā)現(xiàn)這樣的話剛好兩邊的“""”就消失了。下面來(lái)看看最后一個(gè)知識(shí)點(diǎn)條件編譯。
  三、條件編譯
  條件編譯命令#if、#else、#elif、#endif、#ifdef、#ifndef,條件編譯指令的意思很簡(jiǎn)單,跟我們學(xué)習(xí)的if語(yǔ)句類似。
  一般格式
  #if 常量表達(dá)式
  程序段1;
  [#else
  程序段2;]
  #endif
  功能:當(dāng)表達(dá)式為非0(“邏輯真”)時(shí),編譯程序段1,否則編譯程序段2。
  一般格式
  #ifdef 標(biāo)識(shí)符
  程序段1;
  [#else
  程序段2;]
  #endif
  功能:當(dāng)“標(biāo)識(shí)符”已經(jīng)被#define命令定義過(guò),則編譯程序段1,否則編譯程序段2。
  #ifndef 標(biāo)識(shí)符
  程序段1;
  [#else
  程序段2;]
  #endif
  功能:當(dāng)“標(biāo)識(shí)符”未被#define命令定義過(guò),則編譯程序段1,否則編譯程序段2。
  學(xué)習(xí)了條件編譯指令之后,我們?cè)谡{(diào)試代碼的時(shí)候,就不要再隨心所欲的刪減代碼了,如果我們不想某段代碼被編譯就可以使用條件編譯指令來(lái)將其注釋掉。如:
  #if (0)
  注釋代碼段;
  #endif
  就可以實(shí)現(xiàn)代碼的注釋了,需要的時(shí)候也可以將其啟用,而不會(huì)為需要重新編輯代碼時(shí),發(fā)現(xiàn)已被刪除而頭疼了。
  其中值得注意的地方為,常量表達(dá)式在編譯時(shí)求值,所以表達(dá)式只能是常量或者已經(jīng)定義過(guò)的標(biāo)識(shí)符,不能為變量,也不可以為那些在編譯時(shí)候求值的操作符,如sizeof。
  下面來(lái)看段代碼:
  [cpp] view plaincopy#include
  #define N 1
  int main(int argc,char*argv)
  {
  int a=3;
  #if(a)
  printf("#if后面的表達(dá)式為變量\n");
  #endif
  #if(N)
  printf("#if后面的表達(dá)式已定義,且不為0---success\n");
  #else
  printf("#if后面的表達(dá)式已定義,且不為0---fail\n");
  #endif
  return 0;
  }
  運(yùn)行結(jié)果為:
  


  [cpp] view plaincopy#if后面的表達(dá)式已定義,且不為0---success
  Press any key to continue
  看看上面的代碼我們的表達(dá)式為變量a時(shí)并沒有打印出來(lái),所以我們不能在其后的表示中使用變量。如果我們使用sizeof操作符會(huì)怎么樣呢?為了加深印象看看下面的代碼后結(jié)果吧。
  [cpp] view plaincopy#include
  int main(int argc,char*argv)
  {
  int a=9;
  #if(sizeof(a))
  printf("#if后面的表達(dá)式含有sizeof操作符\n");
  #endif
  return 0;
  }
  編譯出現(xiàn)了如下錯(cuò)誤:
  [cpp] view plaincopyfatal error C1017: invalid integer constant expression
  所以我們?cè)谑褂脳l件編譯的時(shí)候要牢記這兩點(diǎn),常量表達(dá)式不能為變量和含有sizeof等在編譯時(shí)求值的操作符。
  接下來(lái)看看這里要講的最后一個(gè)#pragma指令。
  一般格式為:
  #pragma 參數(shù)
  下面給出幾種經(jīng)常使用的形式
  1、#pragma message("消息")
  看看下面一段代碼。
  [cpp] view plaincopy#include
  #define FDSA
  int main(int argc,char*argv)
  {
  #ifdef FDSA
  #pragma message("FDSA 已經(jīng)定義過(guò)了")
  #endif
  return 0;
  }
  編譯的時(shí)候我們可以在編譯輸出窗口中看到了輸出“FDSA 已經(jīng)定義過(guò)了”,通過(guò)這種方式我們可以在一些我們想要的地方輸出很多我們需要的信息。
  2、#pragma once
  如果我們?cè)陬^文件的開頭部分加入這條指令,那么就能保證我們的頭文件僅僅被編譯一次。
  3、#pragma hdrstop
  該指令表示編譯頭文件到此為止,后面的無(wú)需在進(jìn)行編譯了。
  4、#pragma pack()
  設(shè)定字節(jié)的對(duì)齊長(zhǎng)度,這個(gè)指令我們?cè)凇禖語(yǔ)言的那些小秘密之字節(jié)對(duì)齊》中已經(jīng)講解了,在此不再?gòu)?fù)述。
  5、#pragma warning(disable:M N;once:H;error:K)
  表示不顯示M和N號(hào)的警告信息,H號(hào)警告信息只報(bào)告一次,把K號(hào)警告信息作為一個(gè)錯(cuò)誤來(lái)處理。
  到此關(guān)于預(yù)處理的講解就結(jié)束了。由于本人水平有限,博客中的不妥或錯(cuò)誤之處在所難免,殷切希望讀者批評(píng)指正。同時(shí)也歡迎讀者共同探討相關(guān)的內(nèi)容,如果樂(lè)意交流的話請(qǐng)留下你寶貴的意見。
                                
本文地址:http://www.qingdxww.cn/thread-160521-1-1.html     【打印本頁(yè)】

本站部分文章為轉(zhuǎn)載或網(wǎng)友發(fā)布,目的在于傳遞和分享信息,并不代表本網(wǎng)贊同其觀點(diǎn)和對(duì)其真實(shí)性負(fù)責(zé);文章版權(quán)歸原作者及原出處所有,如涉及作品內(nèi)容、版權(quán)和其它問(wèn)題,我們將根據(jù)著作權(quán)人的要求,第一時(shí)間更正或刪除。
您需要登錄后才可以發(fā)表評(píng)論 登錄 | 立即注冊(cè)

廠商推薦

  • Microchip視頻專區(qū)
  • 5分鐘詳解定時(shí)器/計(jì)數(shù)器E和波形擴(kuò)展!
  • 為何選擇集成電平轉(zhuǎn)換?
  • PIC18-Q71系列MCU概述
  • 基于CEC1712實(shí)現(xiàn)的處理器SPI FLASH固件安全彈性方案培訓(xùn)教程
  • 貿(mào)澤電子(Mouser)專區(qū)
關(guān)于我們  -  服務(wù)條款  -  使用指南  -  站點(diǎn)地圖  -  友情鏈接  -  聯(lián)系我們
電子工程網(wǎng) © 版權(quán)所有   京ICP備16069177號(hào) | 京公網(wǎng)安備11010502021702
快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 日韩成人精品 | 国产欧美一区二区三区免费 | 久久er国产精品免费观看2 | 国产欧美日韩精品专区 | 精品视频香蕉尹人在线 | 黄色试频 | 国产欧美日韩中文字幕 | 一级黄色片aaa | 久草精品在线观看 | 日韩免费观看的一级毛片 | 欧美激情精品久久久久久大尺度 | 一区二区三区www | 色老二精品视频在线观看 | 一个人www免费观看视频 | 欧美另类videos高清精品 | 国产成人a一区二区 | 青青草国产精品人人爱99 | 欧美高清一区二区三 | 免费一级毛片在线播放不收费 | 手机看片久久国产免费不卡 | 麻豆国产原创 | 四虎影音先锋 | 最新国产午夜精品视频成人 | 麻豆精品久久久 | 日韩一级黄色大片 | 四虎成人精品在永久免费 | 亚洲精品网站在线观看不卡无广告 | 国内毛片视频 | 国产成人综合91精品 | 日本一区二区三区精品 | 99热免费观看 | 奇米精品一区二区三区在线观看 | 中文字幕成人免费视频 | 久久精品国产曰本波多野结衣 | 免费视频久久看 | 岛国成人 | 亚洲激情视频在线观看 | 久久99热精品这里久久精品 | 欧美日韩国产免费一区二区三区 | 日韩免费精品视频 | 日本a级黄|