C++ macro(巨集)使用小結

来源:http://www.cnblogs.com/decade-dnbc66/archive/2016/04/04/5350160.html
-Advertisement-
Play Games

談起C++中的巨集,我們第一個想到的應該就是“#define”,它的基本語法長得像這樣: 巨集的聲明和普通的函數聲明很像,但是兩者之間有本質的區別:C++函數在運行時(runtime)才執行代碼段;而巨集則是在預編譯時期(preprocessor)執行代碼段。下麵簡單介紹一下幾個巨集的應用。 一、考慮下麵的 ...


  談起C++中的巨集,我們第一個想到的應該就是“#define”,它的基本語法長得像這樣:

1 #define macroname(para1, para2, para3, ... ,paran) macro-body

  巨集的聲明和普通的函數聲明很像,但是兩者之間有本質的區別:C++函數在運行時(runtime)才執行代碼段;而巨集則是在預編譯時期(preprocessor)執行代碼段。下麵簡單介紹一下幾個巨集的應用。

 

一、考慮下麵的代碼段:

1 #define PLUS_ONE(x) ((x) + 1)
2 int x=PLUS_ONE(12);
>>>x=((12) + 1)
>>>x=13

  這是最簡單的應用,用macro-body替換macroname;和C函數不一樣的是,巨集是沒有返回值的,本身表達式的值將作為返回值傳回。

 

二、考慮下麵的代碼段:

1 #define x 1+2
2 int t=x*3;
3 std::cout<<t<<'\n';

  那麼輸出t的值會是什麼呢?答案也許不是你期望中的9,而是7。原因很簡單,#define的替換實質上是表達式的替換,將上述代碼里的巨集展開後將變成這樣:

  int t = 1 + 2 * 3;   //t = 7

  這種結果顯然不是我們願意看到的,而且這種錯誤是很難察覺的,完全沒有語法錯誤和語義錯誤;不過要解決這個問題也很容易,將表達式括起來就行了:  

1 #define x (1+2)
>>>int t = (1+2)*3=9

  不過這種使用巨集的方法是不推薦的,因為容易引起一些不必要且難以察覺的錯誤。在C++里,我們完全可以這樣聲明x,也能達到同樣的目的:  

1 const int x=3;  //聲明常數推薦用const關鍵字

 

三、Preprocessor預先定義好的值;

__FILE__ :編譯的文件的絕對路徑;

__LINE__ :當前行號;

__TIME__ :當前時間;

__DATE__ :當前日期。

 

四、C語言中macro的設計初衷之一是關於內聯函數。如果我們定義一個求較大值的MAX函數:

1 #define MAX(a,b) ((a)>(b)?(a):(b))
>>>int myInt=MAX(x,y)
>>>int myInt=((x)>(y)?(x):(y))  //上一行調用的巨集將直接這樣插入到代碼段里

  如果我們將MAX寫成一個一般的函數,那麼我們調用MAX將有以下兩個過程:①調用名稱為MAX的函數 ②將比較得到的值返回。顯然在這兩種方案中,macro的方案更較高效,因為它省略的函數調用的開銷,直接能得到結果(相當於inline函數的用法,這裡不展開講inline了)。

 

五、字元串操作函數

  看如下macro定義:

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

  這裡的參數a和b實際上都是以string的方式傳遞的,例如MAX(10,12)返回的是字元串"12",而不是整型的12。預處理器提供兩種方式處理string類型的參數傳遞。

1、stringizing operator '#':返回一個C風格的字元串;

1 #define TEST(n) std::cout << #n << " is " << (n) << std::endl
>>>int x= 6;
>>>TEST(x*2);  //std::cout << "x*2" << " is " << (x*2) << std::endl

  最終得到的結果是:x*2 is 12

  那麼這種看似tricky的語法有什麼用呢?其實,當上述C++代碼被翻譯成機器碼時,所有和變數x相關的概念或者語句都會被“消滅”,因為變數只會存在於C++代碼層;而通過stringizing operator,讓我們以字元串的形式保存一部分C++源代碼變得可能,這可以應用於寫一些“自我診斷(糾錯)”的函數中,有機會再深入介紹吧!

2、string concatenation operator '##':顧名思義,字元串連接運算元:

1 #define TEST2(type) type ones_##type
>>>TEST2(int);
>>>int ones_type;  //這個巨集的功能其實就是聲明一個任意類型的,如int的變數,名字叫做ones_type

  這個沒感覺有什麼特別的用途,trick。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文主要介紹一個在MySQL命令行下執行腳本文件的例子,通過這個例子讓我們來瞭解一下在命令行下MySQL是怎樣執行腳本的吧。現在我們開始介紹這一過程。 1.首先編寫sql腳本,保存為的:book.sql,內容如下: 2.進入MySQL命令行 第一種方式:在未連接資料庫的情況下,輸入 mysql -h ...
  • 1.2 產品特點 Laxcus大數據管理系統運行在電腦集群上,特別強調軟體對分佈資源可隨機增減的適應性。這種運行過程中數據動態波動和需要瞬時感知的特點,完全不同與傳統的集中處理模式。這個特性衍生出一系列的新變化,需要重新審視產品的目標,設計新的架構,當我們把這些需求和定位綜合起來,然後逐一分解歸併 ...
  • 本文講述如何升級Debian8的內核到4.5版本 0x01:去linux kernel官網https://www.kernel.org/下載4.5的內核,選擇tar.xz格式 0x02:想辦法把下載好的包弄進你的虛擬機或...直接你的物理機 0x03:解壓 有的朋友可能沒見過tar.xz格式的包,解 ...
  • input_manager.h #ifndef _INPUT_MANAGER_H #define _INPUT_MANAGER_H #include #define INPUT_TYPE_STDIN 0 #define INPUT_TYPE_TOUCHSCREEN 1 #define INPUT_V... ...
  • 某些環境下(如WIN PE)windows自帶的選擇文件夾api不能使用或者體驗不佳。現在利用GetOpenFileName的回掉參數實現了選擇文件夾選擇功能。 參考:http://blog.csdn.net/norsd/article/details/3476606 ...
  • 這學期我們學操作系統,所以得寫個PCB。 於是我借鑒了一下windows的PCB,寫了這個 那個SingleLinkedList是我自定義的 ...
  • list也就是列表的意思,可以存儲一組數據集合,比如classmates=['zhangsan','lisi','123']每個數據用單引號包裹,逗號隔開。 list是一個有序列表,可以向其中添加單元,在末尾追加 一個數據classmates.append('Adam'),也可以在任意位置添加數據, ...
  • 方法表集合 前面的魔數,次版本號,主板本號,常量池入口,常量池,訪問標誌,類索引,父類索引,介面索引集合,欄位表集合,那麼再接下來就是方法表了. 方法表集合 前面的魔數,次版本號,主板本號,常量池入口,常量池,訪問標誌,類索引,父類索引,介面索引集合,欄位表集合,那麼再接下來就是方法表了. 方法表的 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...