簡體   English   中英

什么會使 C++ 預處理器宏成為公認的開發工具?

[英]What would make C++ preprocessor macros an accepted development tool?

顯然C++ 中的預處理器宏是

C++ 社區有理由害怕和回避。

但是,在某些情況下C++ 宏是有益的

將預處理器宏視為非常有用,並且可以以非常直接的方式減少重復代碼——

- 給我留下一個問題,究竟是什么讓預處理器宏“邪惡”,或者,正如問題標題所說,預處理器宏需要哪些功能(或刪除功能)才能使它們作為“好”有用" 開發工具(而不是一個大家在使用時都害臊的填空題)。 (畢竟,Lisp 語言似乎包含宏。)

請注意:這與#include#pragma#ifdef無關 這是關於#define MY_MACRO(...)...

注意:我不打算讓這個問題變得主觀。 如果您認為是,請隨時投票將其移至programmers.SE。

宏被廣泛認為是邪惡的,因為預處理器是一個愚蠢的文本替換工具,幾乎沒有 C/C++ 知識。

C++ FAQ Lite中可以找到為什么宏是邪惡的四個很好的理由。

在可能的情況下,模板和內聯函數是更好的選擇。 我能想到為什么 C++ 仍然需要預處理器的唯一原因是用於#include和注釋刪除。

一個廣受爭議的優勢是使用它來減少代碼重復; 但是正如您從 boost 預處理器庫中看到的那樣,必須付出很多努力來濫用預處理器來處理諸如循環之類的簡單邏輯,從而導致語法丑陋。 在我看來,用真正的高級編程語言編寫腳本來生成代碼而不是使用預處理器是一個更好的主意。

大多數預處理器濫用來自誤解,引用 Paul Mensonides( Boost.Preprocessor庫的作者)的話:

幾乎所有與濫用預處理器有關的問題都源於試圖使類對象宏看起來像常量變量,而類函數宏調用看起來像底層語言 function 調用。 充其量,類似函數的宏調用和 function 調用之間的相關性應該是偶然的。 永遠不應將其視為目標。 這是一種從根本上破碎的心態。

由於預處理器很好地集成到 C++ 中,因此更容易模糊界限,大多數人看不出有什么區別。 比如讓別人寫一個宏把兩個數相加,大多數人會這樣寫:

#define ADD(x, y) ((x) + (y))

這是完全錯誤的。 通過預處理器運行它:

#define ADD(x, y) ((x) + (y))
ADD(1, 2) // outputs ((1) + (2))

但答案應該是 3,因為將 1 加到 2 是 3。然而,編寫了一個宏來生成 C++ 表達式。 不僅如此,它可以被認為是 C++ function,但它不是。 這就是導致濫用的地方。 它只是生成一個 C++ 表達式和一個 function 是 go 的更好方法。

此外,宏根本不像函數那樣工作。 預處理器通過掃描和擴展宏的過程來工作,這與使用調用堆棧調用函數有很大不同。

有時宏生成 C++ 代碼是可以接受的,只要它不模糊線條即可。 就像您使用 python 作為預處理器來生成代碼一樣,預處理器也可以這樣做,並且具有不需要額外構建步驟的優點。

此外,預處理器可以與 DSL 一起使用,例如herehere ,但這些 DSL 在預處理器中具有預定義的語法,用於生成 C++ 代碼。 它並沒有真正模糊線條,因為它使用了不同的語法。

宏有一個顯着的特點——它們很容易被濫用,而且很難調試。 您可以使用宏編寫幾乎任何東西,然后將宏擴展為單行代碼,當沒有任何效果時,您很難調試生成的代碼。

僅此功能就讓人思考十次是否以及如何使用宏來完成他們的任務。

並且不要忘記宏在實際編譯之前會被擴展,因此它們會自動忽略名稱空間、范圍、類型安全和大量其他內容。

宏最重要的是沒有scope,不關心上下文。 它們幾乎是一個轉儲文本替換工具。 因此,當您 #define max(.... 時,任何有最大值的地方都會被替換;因此,如果有人在其標題中添加了過於通用的宏名稱,他們往往會影響他們不打算影響的代碼。

另一件事是,如果不小心使用它們,它們會導致代碼非常難以閱讀,因為沒有人可以很容易地看到宏可以計算出的結果,尤其是在嵌套多個宏時。

一個好的指導方針是選擇唯一的名稱,並且在生成樣板代碼時,盡快#undef 它們以免污染命名空間。

此外,它們不提供類型安全或重載。

有時宏可以說是生成樣板代碼的好工具,例如在 boost.pp 的幫助下,您可以創建一個宏來幫助您創建枚舉,例如:

ENUM(xenum,(a,b,(c,7)));

可以擴展到

enum xenum { a, b, c=7 };

std::string to_string( xenum x ) { .... }

像 assert() 這樣需要對 NDEBUG 做出反應的東西通常也更容易實現為宏

C 開發人員使用宏和 C++ 開發人員使用模板有很多用途。

顯然存在一些有用的極端情況,但大多數時候,C 世界的壞習慣適用於 C++ 的人們相信有這樣一種稱為 C/C++ 的語言

所以說“它是邪惡的”比冒着開發者濫用它們的風險更容易。

強迫程序員對宏使用正確的命名......以及更好的工具來跟蹤宏的替換將解決我的大部分問題。 到目前為止,我真的不能說我遇到了重大問題......這是你自己燒傷自己並學會以后特別小心的事情。 但他們迫切需要更好地與 IDE、調試器集成。

  1. 宏不提供類型安全
  2. 參數執行兩次的問題,例如 #define MAX(a,b) ((a)>(b)? (a): (b)) 並將其應用於 MAX(i++, y--)
  3. 調試問題,因為它們的名稱不會出現在符號表中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM