在《C宏——智者的利刃,愚者的恶梦! 》一文中,提到了一种使用宏的方式 —— “例一、用C宏,书写代码更简洁”。
《C宏——智者的利刃,愚者的恶梦! 》: http://www.vckbase.com/document/viewdoc/?id=1454
《C宏——智者的利刃,愚者的恶梦! 》: http://blog.vckbase.com/smileonce/archive/2005/03/27/4081.html
本文章分别给出C++和C中不使用宏的实现方式。
首先,书写代码更简洁是否是优点?
有兴趣的读者请看看《设计Qt风格的C++API》一文中“便利陷阱” (The Convenience Trap) 一节。
中文: http://blog.csdn.net/TopLanguage/archive/2008/02/21/2111467.aspx
英文: http://doc.trolltech.com/qq/qq13-apis.html
【永远记住代码一次写就,之后需要不断的阅读并理解。】
【Keep in mind that code is written more than once but has to be understood over and over again.】
如果真要达到笑笑文中——【mbuf的属性,完全可以压扁到一个平面上去看】——这个目的,除了宏,也是有其他方法的。
在这里说明一下,笑笑在文中并没有给出struct mbuf的完整定义。
我没有linux,Cygwin也删掉了,安装挺麻烦的……
顺藤摸瓜的下载了一部分文件:
http://opengrok.creo.hu/dragonfly/xref/src/sys/sys/mbuf.h
http://opengrok.creo.hu/dragonfly/xref/src/sys/sys/param.h
http://opengrok.creo.hu/dragonfly/xref/src/sys/net/netisr.h
http://opengrok.creo.hu/dragonfly/xref/src/sys/net/netmsg.h
http://opengrok.creo.hu/dragonfly/xref/src/sys/sys/thread.h
http://opengrok.creo.hu/dragonfly/xref/src/sys/sys/msgport.h
企图拼出一个完整的struct mbuf定义,但实在太麻烦,这里就放弃了 ……
所以只用一个简单的例子来说明如何不使用宏来达到这一目的。
当然,也会说明如果结构体更复杂该如何扩展。
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
结构体定义:
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**//** structure definition */
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**//* simple Point & Size structure */
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
typedef struct Point_
{
int x;
int y;
} Point;
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
typedef struct Size_
{
int width;
int height;
} Size;
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**//** complex Rect structrue */
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
typedef struct Rect_
{
Point offset;
Size size;
} Rect;
C++方案:
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
C++方案
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
namespace cpp
{
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
class RectAccessor
{
public:
RectAccessor(Rect& r)
:x(r.offset.x)
,y(r.offset.y)
,width(r.size.width)
,height(r.size.width)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{ }
public:
int& x;
int& y;
int& width;
int& height;
};
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
void test(int (&arr)[4],Rect* r)
{
RectAccessor ac(*r);
// 同一平面
ac.x = arr[0];
ac.y = arr[1];
ac.width = arr[2];
ac.height = arr[3];
printf("%d %d %d %d\n",ac.x,ac.y,ac.width,ac.height);
}
}
const怎么办?
(对const的考虑,C++程序员总是比C程序员要多一点,不是吗?)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
const accessor
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**//** const accessor */
// 再定义一个const存取器不就完了?
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
class ConstRectAccessor
{ /**//**/ };
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
//如果觉得这样名字不统一,不好看,也可以这样
template<bool is_constant>
class RectAccessor;
template<>
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
class RectAccessor<false>
{ /**//* 同上面那个RectAccessor */ };
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
class RectAccessor<true>
{ /**//* 同上面那个ConstRectAccessor */ };
对更复杂的结构体,该方法的扩展是很容易的事情:在构造函数的成员初始化列表里写就是了。
C呢?是不是只能使用宏?当然不是。
C的方案:
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
union
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
namespace c
{
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
typedef union RectAccessor_
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
struct S1
{
int x;
int y;
int width;
int height;
};
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
struct S2
{
Point offset;
Size size;
};
Rect rect;
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
} RectAccessor;
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
__declspec(noinline) void test(int (&arr)[4],Rect* r)
{
RectAccessor* ac = (RectAccessor*) r;
// 同一平面
ac->x = arr[0];
ac->y = arr[1];
ac->width = arr[2];
ac->height = arr[3];
printf("%d %d %d %d\n",ac->x,ac->y,ac->width,ac->height);
}
}
对const, 转型的时候,注意使用合适的指针类型就可以了。
想更复杂的结构体扩展:
如果对上面的方案不理解,甚至对mbuf都不理解,最好还是老老实实的使用全名。
永远记得,代码读的次数比写的次数多!
上面的方案,是利用了一个特性,叫“匿名联合”还别的什么东东。
含义大概是这样:
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
anonymous
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
union U
{
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
struct /**//** anonymous */
{
t11 v11;
t12 v12;
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//* more members */
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
} /**//** anonymous */;
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
struct /**//** anonymous */
{
t21 v21;
t22 v22;
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//* more members */
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
} /**//** anonymous */;
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//** more structures */
};
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**//* 那么就可以*/
U u;
u.v11; u.v12; u.v21;
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
经测试,上面两种方案,在VC8 O2优化下,生成的机器码同不使用Accessor
完全一致。
GCC就没有测试了,看不懂它的汇编……
对宏的方案(也就是mbuf.h中提供的)的改进:
简直无法想象!居然在
头文件 中
定义如此
普遍 的
小写 宏名字!
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
宏改进方案:
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**//** mbuf_accessor_define.h */
#define m_next m_hdr.mh_next
#define m_len m_hdr.mh_len
#define m_data m_hdr.mh_data
#define m_type m_hdr.mh_type
#define m_flags m_hdr.mh_flags
#define m_nextpkt m_hdr.mh_nextpkt
#define m_pkthdr M_dat.MH.MH_pkthdr
#define m_ext M_dat.MH.MH_dat.MH_ext
#define m_pktdat M_dat.MH.MH_dat.MH_databuf
#define m_dat M_dat.M_databuf
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**//** mbuf_accessor_undef.h */
#undef m_next
#undef m_len
#undef m_data
#undef m_type
#undef m_flags
#undef m_nextpkt
#undef m_pkthdr
#undef m_ext
#undef m_pktdat
#undef m_dat
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**//* 需要的时候 */
#include <mbuf_accessor_define.h>
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**//* 使用简写 */
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**//* 使用简写 */
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**//* 使用简写 */
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**//* 然后立刻取消定义 */
#include <mbuf_accessor_undef.h>
PS:C程序员总说C++的语言特性有心智包袱,难道宏就不算心智包袱?
物理老师从来都是这么写: F = M*A;
没见任何一个物理老师会这么写: F = multiply(M,A);
如果是,请立刻和同学打赌说他是程序员,而且很有可能是C程序员。
hp_int i1,i2,i3;
// ...
数学老师也总是这么写: hp_int icpp = i1 + i2 * i3;
不会有数学老师这么写:
hp_int ic;
hp_assign(&i2,&ic);
hp_multiply(&i3,&ic);
hp_plus(&i1,&ic);
或者这么写:
hp_plus(&i1,hp_multiply(&i3,hp_assgin(&i2,&ic) ) );
(hp —— 高精度, 对矩阵也是同样)
C程序员说,不知道 string s = s1 + s2 + s3;背后做了什么。
C++程序员说,由库决定。
C程序员说,我对库中那些精巧的技术不感兴趣(不熟悉,不愿意学)。
C++程序员说,就对宏技术感兴趣?
C程序员说,宏效率高。
C++程序员说, 如果 string s = s1 + s2 + s3;可以实现得比 strcat(strcat(strcat(....) 效率更高,你信不信?
C++程序员再说,如果可以自然的写出hp_int icpp = i1 + i2 * i3;有正确的运算优先级,效率与hp_plus(&i1,hp_multiply(&i3,hp_assgin(&i2,&ic) ) );等同,你还愿意用后者?
C程序员说,那些实现都是心智包袱,我不喜欢。
C++程序员说,宏算不算心智包袱?你怎么就喜欢了?
总之,这只是一种不愿学习的心态,一种手拿锤子见什么都是钉子的心态。
Linus年纪也不算大……才40岁…… 哎……
posted on 2009-02-19 21:48
OwnWaterloo 阅读(1958)
评论(4) 编辑 收藏 引用