作者bnsblue (想當你的天空)
看板EE_DSnP
標題[轉錄] So, what's wrong with using macros?
時間Thu Oct 22 09:43:01 2009
1F:推 dryman:如果全部功能都測試完畢,可以將一些for迴圈寫成macro 10/22 05:43
2F:→ dryman:只要名稱取得好,不妨礙閱讀程式碼的話,macro也是很棒的 10/22 05:46
3F:→ dryman:ex: FOR_PTR_TO_END 10/22 05:46
4F:推 timrau:這種macro自己用還好,trace別人的程式遇到這種會抓狂 10/22 07:15
5F:→ timrau:debugger實在是對macros幾乎無能為力.... 10/22 07:15
來看看C++的發明人Bjarne Stroustrup怎麼看macros
摘要
1. Macros的定義並不會被scope還有其他的type rules擋住 -- 這常會造成問題
2. Macros是會被preprocess的,這使得人看到的code和compiler看到的code不一樣
3. 做為一個程式維護員,看到把資訊"藏得很隱密"的macro,只能當場傻眼
4. 不細心書寫的macros常常會造成程式設計師對自己寫的程式「語意」上的誤解--
雖然macro只是個代換而已
5. Bjarne Stroustrup自己一點都不想再去改進C++中macro的機制
他認為用C++裡面其他的語法可以很恰當地取代macro的使用
============================================================
So, what's wrong with using macros?
Bjarne Stroustrup
出處:
http://www.research.att.com/~bs/bs_faq2.html#macro
Macros do not obey the C++ scope and type rules. This is often the cause of
subtle and not-so-subtle problems. Consequently, C++ provides alternatives
that fit better with the rest of C++, such as inline functions, templates,
and namespaces.
Consider:
#include "someheader.h"
struct S {
int alpha;
int beta;
};
If someone (unwisely) has written a macro called "alpha" or a macro called
"beta" this may not compile or (worse) compile into something unexpected. For
example, "someheader.h" may contain:
#define alpha 'a'
#define beta b[2]
Conventions such as having macros (and only macros) in ALLCAPS helps, but
there is no language-level protection against macros. For example, the fact
that the member names were in the scope of the struct didn't help: Macros
operate on a program as a stream of characters before the compiler proper
sees it. This, incidentally, is a major reason for C and C++ program
development environments and tools have been unsophisticated: the human and
the compiler see different things.
Unfortunately, you cannot assume that other programmers consistently avoid
what you consider "really stupid". For example, someone recently reported to
me that they had encountered a macro containing a goto. I have seen that also
and heard arguments that might - in a weak moment - appear to make sense. For
example:
#define prefix get_ready(); int ret__
#define Return(i) ret__=i; do_something(); goto exit
#define suffix exit: cleanup(); return ret__
void f()
{
prefix;
// ...
Return(10);
// ...
Return(x++);
//...
suffix;
}
Imagine being presented with that as a maintenance programmer; "hiding" the
macros in a header - as is not uncommon - makes this kind of "magic" harder
to spot.
One of the most common subtle problems is that a function-style macro doesn't
obey the rules of function argument passing. For example:
#define square(x) (x*x)
void f(double d, int i)
{
square(d); // fine
square(i++); // ouch: means (i++*i++)
square(d+1); // ouch: means (d+1*d+1); that is, (d+d+1)
// ...
}
The "d+1" problem is solved by adding parentheses in the "call" or in the
macro definition:
#define square(x) ((x)*(x)) /* better */
However, the problem with the (presumably unintended) double evaluation of
i++ remains.
And yes, I do know that there are things known as macros that doesn't suffer
the problems of C/C++ preprocessor macros. However, I have no ambitions for
improving C++ macros. Instead, I recommend the use of facilities from the C++
language proper, such as inline functions, templates, constructors (for
initialization), destructors (for cleanup), exceptions (for exiting
contexts), etc.
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 140.112.218.128
※ 編輯: bnsblue 來自: 140.112.218.128 (10/22 10:04)