作者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)