C++ 之 巨集定義

来源:https://www.cnblogs.com/xinxue/archive/2022/11/28/16893770.html
-Advertisement-
Play Games

巨集在 C 語言中非常重要,但在 C++ 中卻無甚大用,普遍的共識:儘量避免使用巨集 C++ 之父 Bjarne 在《C++ Programming Language》中寫到 Avoid macros 《Effective C++》 條款 2 Prefer const, enum, and inline ...


    巨集在 C 語言中非常重要,但在 C++ 中卻無甚大用,普遍的共識:儘量避免使用巨集

    C++ 之父 Bjarne 在《C++ Programming Language》中寫到

  • Avoid macros

    《Effective C++》 條款 2

  • Prefer const, enum, and inline to #define

    谷歌 C++ 編碼規範,關於巨集的描述

  • Avoid defining macros, especially in headers
  • Do not use macros to define pieces of a C++ API

1  禁用巨集

    谷歌 C++ 規範中,禁用巨集的情況有三種:頭文件、API 介面、程式文本

    頭文件中禁用巨集,規範里寫的很明確:

  • Don't define macros in a .h file.

    對於 C++ API 介面,則是:

  • Do not use macros to define pieces of a C++ API

    因此,如下形式的巨集,是禁止的

class PANDA_TYPE(Foo) {
  // ...
 public:
  EXPAND_PUBLIC_PANDA_API(Foo)

  EXPAND_PANDA_COMPARISONS(Foo, ==, <)
};

    程式文本中禁用巨集,尤其是用 ## 來替換變數名

  • Don't use macros for program text manipulation
  • Prefer not using ## to generate function/class/variable names. 

    例如,下麵代碼是要避免的

#define CAT(a, b) a ## b
#define STRINGIFY(a) #a

void f(int x, int y)
{
    string CAT(x, y) = "asdf";   // BAD: hard for tools to handle (and ugly)
    string sx2 = STRINGIFY(x);
    // ...
}  

2  替代巨集

    《Effective C++》 條款 2:用 const, enum 或 inline 來替代巨集

    用巨集來表示常量和函數,是不推薦的

#define PI 3.14

#define SQUARE(a, b) (a * b)

    可用 constexpr 和 模板函數來替代,這樣的好處:constexpr 定義的常量 kPI 會進入符號表,能被編譯器識別到,編譯報錯時會提示 kPI 錯誤

    而定義在 .h 中的巨集,如果編譯出錯,只會提示 3.14 這個數值的錯誤,對於不是自己寫的頭文件,且常數含義未知時,很難查到錯誤來源

constexpr double kPI = 3.14;

template<typename T> 
T square(T a, T b) { return a * b; }  

    同樣,如下代碼也是需要避免的

// webcolors.h (third party header)
#define RED   0xFF0000
#define BLUE  0x0000FF

// productinfo.h, the following define product subtypes based on color
#define RED    1
#define BLUE   2

int web = BLUE;   // web == 2; probably not what was desired

  可用 enum class 來代替,在 C++11 之 enum class 中也有提及

enum class Web_color { red = 0xFF0000, green = 0x00FF00, blue = 0x0000FF };
enum class Product_info { red = 0, purple = 1, blue = 2 };

int webby = blue;   // error: be specific
Web_color web = Web_color::blue;  

3  使用巨集

    雖然巨集在 C++ 中如此被嫌棄,但為了相容 C 語言,也不能直接將其刪掉,這也是阻礙 C++ 發展的歷史包袱

    在某些方面,巨集還是有點價值的,比如:頭文件的保護巨集

#ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_

...

#endif  // FOO_BAR_BAZ_H_

     還有一些預定義好的巨集

__cpluplus
__DATE__
__FILE__
__LINE__

    在代碼可讀性上,巨集往往會有意想不到的效果,如《The Art of Readable Code》中的例子

void AddStats(const Stats& add_from, Stats* add_to) 
{
    add_to->set_total_memory(add_from.total_memory() + add_to->total_memory());
    add_to->set_free_memory(add_from.free_memory() + add_to->free_memory());
    add_to->set_swap_memory(add_from.swap_memory() + add_to->swap_memory());
    add_to->set_status_string(add_from.status_string() + add_to->status_string());
    add_to->set_num_processes(add_from.num_processes() + add_to->num_processes());
    ...
}

    為了增強可讀性,使用巨集定義,可改為如下形式

void AddStats(const Stats& add_from, Stats* add_to)
{
#define ADD_FIELD(field) add_to->set_##field(add_from.field() + add_to->field())
    ADD_FIELD(total_memory);
    ADD_FIELD(free_memory);
    ADD_FIELD(swap_memory);
    ADD_FIELD(status_string);
    ADD_FIELD(num_processes);
    ...
#undef ADD_FIELD
}

 當必須使用巨集時,註意如下幾點:

  • If you must use macros, use names with capital letters
  • Name macros with a project-specific prefix
  • #define macros right before you use them, and #undef them right after.

 

參考資料

    C++ Core GuideLines

    谷歌 C++ 編碼規範 - Preprocessor Macros

   《The Art of Readable Code》 chapter 8

 

後記

    寫完博文,當我還沉浸在搞清一個 C++ 知識點的興奮中時,突然想到魯迅筆下的《孔乙己》,這篇博文,不就是教茴字四種寫法的現代版麽?

    孔乙己的悲劇,更多是因時代巨變所致,是舊社會一代讀書人的命運縮影,如果時代沒有變,興許茴字的寫法,也是科舉考試中的一個知識點。

    然而,孔乙己還是有一技之長的,"幸而寫得一筆好字,便替人家抄抄書,換一碗飯吃"。在如今經濟停滯甚至衰退的浪潮下,我又有什麼一技之長 "換一碗飯吃" 呢? 

    寫到此,我也沒有答案,孔乙己 = 恐怕以為是自己,只能以《孔乙己》的結尾警示自己:我到現在終於沒有見——大約孔乙己的確失業了... 

 

原文鏈接: http://www.cnblogs.com/xinxue/

專註於機器視覺、OpenCV、C++ 編程


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

-Advertisement-
Play Games
更多相關文章
  • 前言: 前天我們學了 ref 和 reactive ,提到了響應式數據和 Proxy ,那我們今天就來瞭解一下,vue3 的響應式 在瞭解之前,先複習一下之前 vue2 的響應式原理 vue2 的響應式: 原理: 對象類型:通過 Object.defineProperty() 對象的讀取,修改進行攔 ...
  • 當遇到生產問題,你是怎麼處理的,斬草除根?or 頭疼醫頭/腳疼醫腳? 下麵幾個,看看是否中招le!你也可以說,我肯定沒有這麼草率 1 ​併發導致數據表裡出現了同樣的數據 -加唯一索引 2 程式fullGC頻繁 -修改程式啟動參數,加大堆記憶體 3 mq消息堵塞 -重啟服務…重啟服務不奏效?清空隊列 4 ...
  • 前言 此篇博文內容續接的是 UML建模語言、設計原則、創建型設計模式 的內容,有興趣的可以點前面的鏈接去看一下 3.2、行為型 這類設計模式是專門用於:對象間的高效溝通和職責委派 * 3.2.1、責任鏈模式 定義:責任鏈模式又名職責鏈模式,指的是:對某個請求的所有處理構成一條鏈,如果鏈上的某一處理者 ...
  • # 面向對象是非常重要的! # 抽象,是個思想,結構 # 小明 小紅 小雨 都是人 # 海爾洗衣機 海東洗衣機 海西洗衣機 都是洗衣機 # 貓 狗 熊貓 都是動物 # 藍圖 # # class WashingMachine: # 類名一般是大駝峰 # pass # # 特征是屬性 # age = 2 ...
  • 多線程實現socket通信伺服器端代碼 import socket import threading class MyServer(object): def __init__(self): # 初始化socket self.server = socket.socket(socket.AF_INET, ...
  • Filter過濾器 1.Filter過濾器說明 為什麼需要過濾器? 先來看一個例子: 我們在登錄網站頁面時,需要先進行登錄驗證。 用戶訪問的正常的流程應該是: 用戶先通過登錄頁面進行驗證,然後才可以訪問各種頁面。 為了防止用戶繞過登錄驗證,我們需要在每個頁面進行驗證, 獲取session,驗證用戶是 ...
  • 一.小結 1.類是對象的模板。它定義對象的屬性,並提供創建對象的構造方法以及對對象進行操作的方法。 2.類也是一種數據類型。可以用它聲明對象引用變數。對象引用變數中似乎存放了一個對象,但事實上,它包含的只是對該對象的引用。嚴格地講,對象引用變數和對象是不同的,但是大多數情況下,它們的區別是可以忽略的 ...
  • 版權聲明:原創不易,本文禁止抄襲、轉載,侵權必究! 一、pywifi簡介&安裝 開發環境:Windows10 Python3.6.4 第三方庫:pywifi-1.1.12 IDE :PyCharm/Sublime Text pywifi簡介: pywifi是python中一個用於操作無線介面的第三方 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...