巨集(Macro)是邪惡的。
它很好用,可以簡化我們的程式碼,節省很多Coding的時間。
但是它暗地裡在破壞我們程式碼的物件架構,在物件封裝中到處鑽孔。
所以,前兩天,我將程式碼裡頭的
#include "windowsx.h"
給拔掉。
這個標頭檔,定義了很多巨集,有些是簡化windows訊息程式碼,有些是簡化windows API。平常是很好用的啦,但是,好死不死的,我有個樹狀結構的物件,裡頭有幾個函式-- GetFirstChild, GetNextChild, ... 就跟windows API的巨集衝突到了。
好端端擺在物件中的GetFirstChild函式,被windows API的GetFirstChild巨集取代掉,所以編譯器瞬間開始混亂,看不懂我的程式碼在幹什麼,連錯誤回報也是亂報一通不知所云。
花了時間除錯,拔掉了這些個讓人偷懶的巨集。
所以這巨集真不是好東西。
裹著糖衣的毒藥。
Code Complete的作者在書裡也有說,巨集,能不用就不用,務必謹慎使用。
是啊,別偷懶了,該拔掉的就拔掉吧。
==================================================
其實今天一早,還遇見了另一個類似的問題。
我在數學函式庫裡,定義了一個靜態常數PI (就是圓周率啦),還特別放在一個Math物件中,用Math::PI這樣的語法來存取,避免這種常數定義衝突的狀況。
class Math
{
...
static const float PI;
};
不過,又來了,好死不死,Max SDK裡面也定義了一個PI,而且是直接#define,
#define PI ((float)3.1415926535)
結果我怎麼辦? 我只能先引入自己數學函式庫的標頭檔,然後再引入Max SDK的標頭檔,順序絕對不能換,否則編譯器就會開始錯亂。
5 則留言:
I would like to add prefix to my own macro.
by the way, to avoid Windows macro, I prefer using unix naming converion, such as get_first_child.
I would like to add prefix to my own macro.
by the way, to avoid Windows macro, I prefer using unix naming converion, such as get_first_child.
用一些命名規則來定義巨集,確實也是一種避免衝突的方法,只不過,誰也無法保證絕對不會碰到同樣的命名規則不是?
尤其是當我們引入外部的程式庫的時候,也就很容易碰到這些狀況(就像我今天一大早的體驗....)
所以,我是非常同意Code Complete作者所說的,盡量避免使用這個老是在破壞物件封裝的壞東西。
非常同意,其實絕大部分巨集的作用,都可以用其他方式取代。很多喜歡大量使用巨集的程式設計者,純粹是因為方便和懶惰之故。
PlaySound 也是一個經常會遇到的定義衝突。 XD
我碰到過 win32 的 DrawText。
我碰到這種情況,通常只是簡單地 #undef DrawText。
張貼留言