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
  • 概述:本文代碼示例演示瞭如何在WPF中使用LiveCharts庫創建動態條形圖。通過創建數據模型、ViewModel和在XAML中使用`CartesianChart`控制項,你可以輕鬆實現圖表的數據綁定和動態更新。我將通過清晰的步驟指南包括詳細的中文註釋,幫助你快速理解並應用這一功能。 先上效果: 在 ...
  • openGauss(GaussDB ) openGauss是一款全面友好開放,攜手伙伴共同打造的企業級開源關係型資料庫。openGauss採用木蘭寬鬆許可證v2發行,提供面向多核架構的極致性能、全鏈路的業務、數據安全、基於AI的調優和高效運維的能力。openGauss深度融合華為在資料庫領域多年的研 ...
  • openGauss(GaussDB ) openGauss是一款全面友好開放,攜手伙伴共同打造的企業級開源關係型資料庫。openGauss採用木蘭寬鬆許可證v2發行,提供面向多核架構的極致性能、全鏈路的業務、數據安全、基於AI的調優和高效運維的能力。openGauss深度融合華為在資料庫領域多年的研 ...
  • 概述:本示例演示了在WPF應用程式中實現多語言支持的詳細步驟。通過資源字典和數據綁定,以及使用語言管理器類,應用程式能夠在運行時動態切換語言。這種方法使得多語言支持更加靈活,便於維護,同時提供清晰的代碼結構。 在WPF中實現多語言的一種常見方法是使用資源字典和數據綁定。以下是一個詳細的步驟和示例源代 ...
  • 描述(做一個簡單的記錄): 事件(event)的本質是一個委托;(聲明一個事件: public event TestDelegate eventTest;) 委托(delegate)可以理解為一個符合某種簽名的方法類型;比如:TestDelegate委托的返回數據類型為string,參數為 int和 ...
  • 1、AOT適合場景 Aot適合工具類型的項目使用,優點禁止反編 ,第一次啟動快,業務型項目或者反射多的項目不適合用AOT AOT更新記錄: 實實在在經過實踐的AOT ORM 5.1.4.117 +支持AOT 5.1.4.123 +支持CodeFirst和非同步方法 5.1.4.129-preview1 ...
  • 總說周知,UWP 是運行在沙盒裡面的,所有許可權都有嚴格限制,和沙盒外交互也需要特殊的通道,所以從根本杜絕了 UWP 毒瘤的存在。但是實際上 UWP 只是一個應用模型,本身是沒有什麼許可權管理的,許可權管理全靠 App Container 沙盒控制,如果我們脫離了這個沙盒,UWP 就會放飛自我了。那麼有沒... ...
  • 目錄條款17:讓介面容易被正確使用,不易被誤用(Make interfaces easy to use correctly and hard to use incorrectly)限制類型和值規定能做和不能做的事提供行為一致的介面條款19:設計class猶如設計type(Treat class de ...
  • title: 從零開始:Django項目的創建與配置指南 date: 2024/5/2 18:29:33 updated: 2024/5/2 18:29:33 categories: 後端開發 tags: Django WebDev Python ORM Security Deployment Op ...
  • 1、BOM對象 BOM:Broswer object model,即瀏覽器提供我們開發者在javascript用於操作瀏覽器的對象。 1.1、window對象 視窗方法 // BOM Browser object model 瀏覽器對象模型 // js中最大的一個對象.整個瀏覽器視窗出現的所有東西都 ...