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
  • Dapr Outbox 是1.12中的功能。 本文只介紹Dapr Outbox 執行流程,Dapr Outbox基本用法請閱讀官方文檔 。本文中appID=order-processor,topic=orders 本文前提知識:熟悉Dapr狀態管理、Dapr發佈訂閱和Outbox 模式。 Outbo ...
  • 引言 在前幾章我們深度講解了單元測試和集成測試的基礎知識,這一章我們來講解一下代碼覆蓋率,代碼覆蓋率是單元測試運行的度量值,覆蓋率通常以百分比表示,用於衡量代碼被測試覆蓋的程度,幫助開發人員評估測試用例的質量和代碼的健壯性。常見的覆蓋率包括語句覆蓋率(Line Coverage)、分支覆蓋率(Bra ...
  • 前言 本文介紹瞭如何使用S7.NET庫實現對西門子PLC DB塊數據的讀寫,記錄了使用電腦模擬,模擬PLC,自至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1.Windows環境下鏈路層網路訪問的行業標準工具(WinPcap_4_1_3.exe)下載鏈接:http ...
  • 從依賴倒置原則(Dependency Inversion Principle, DIP)到控制反轉(Inversion of Control, IoC)再到依賴註入(Dependency Injection, DI)的演進過程,我們可以理解為一種逐步抽象和解耦的設計思想。這種思想在C#等面向對象的編 ...
  • 關於Python中的私有屬性和私有方法 Python對於類的成員沒有嚴格的訪問控制限制,這與其他面相對對象語言有區別。關於私有屬性和私有方法,有如下要點: 1、通常我們約定,兩個下劃線開頭的屬性是私有的(private)。其他為公共的(public); 2、類內部可以訪問私有屬性(方法); 3、類外 ...
  • C++ 訪問說明符 訪問說明符是 C++ 中控制類成員(屬性和方法)可訪問性的關鍵字。它們用於封裝類數據並保護其免受意外修改或濫用。 三種訪問說明符: public:允許從類外部的任何地方訪問成員。 private:僅允許在類內部訪問成員。 protected:允許在類內部及其派生類中訪問成員。 示 ...
  • 寫這個隨筆說一下C++的static_cast和dynamic_cast用在子類與父類的指針轉換時的一些事宜。首先,【static_cast,dynamic_cast】【父類指針,子類指針】,兩兩一組,共有4種組合:用 static_cast 父類轉子類、用 static_cast 子類轉父類、使用 ...
  • /******************************************************************************************************** * * * 設計雙向鏈表的介面 * * * * Copyright (c) 2023-2 ...
  • 相信接觸過spring做開發的小伙伴們一定使用過@ComponentScan註解 @ComponentScan("com.wangm.lifecycle") public class AppConfig { } @ComponentScan指定basePackage,將包下的類按照一定規則註冊成Be ...
  • 操作系統 :CentOS 7.6_x64 opensips版本: 2.4.9 python版本:2.7.5 python作為腳本語言,使用起來很方便,查了下opensips的文檔,支持使用python腳本寫邏輯代碼。今天整理下CentOS7環境下opensips2.4.9的python模塊筆記及使用 ...