虽然在C++中推荐使用const代替宏的使用.但是宏还是有它的作用的.比如说##的使用,简单的说是可以在宏里面设置变量.直接上代码:
#include <stdio.h>
#include <process.h>
#define ABC(a,b) ABC_##a(b) //a就相当于宏里的变量
#define ABC_A(b) (b+b) //上一句a传A,或B就调用这两句
#define ABC_B(b) (b*b)
int main(int argc,char *argv[])
{
printf("%d\n",ABC(A,3)); //a=A 调用ABC_A(3) = 6
printf("%d\n",ABC(B,3)); //a=B 调用ABC_B(3) = 9
system("pause");
return 0;
}
好了关于##我所知道的就这个,关于使用,我所知道的是Windwos的消息解析器(<<Windows核心编程>>附录B),一句HANDLE_MSG简化好多问题(不过很少有人直接用SDK编程,都被MFC强奸了),大家直接看HANDLE_MSG的源代码:
/****** Message crackers ****************************************************/
#define HANDLE_MSG(hwnd, message, fn) \
case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn))
.....
#define HANDLE_WM_CREATE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (LPCREATESTRUCT)(lParam)) ? 0L : (LRESULT)-1L)
.....
就选这么点,使用的时候大家可以
HANDLE_MSG(hwnd,WM_CREATE,OnCreate);
宏会展开成什么大家应该可以根据上面例子展开.
好了在介绍个cl的选项 /P(预处理到文件) /EP(预处理到标准输出,没有 #line)有了这两个选项我们就可以将编译器(cl)的预处理文件保存到文件(*.i)(注意:加了这两个选项后编译器不好生成可执行文件,所以权当学习宏使用) VC6.0没有这个选项要手动加,如图:
VS2005就可以可视化选了,如图:
好了我们可以看看生成的文件了:
直接拖到最后可以看到这一段:
LRESULT __stdcall WndProc(HWND hwnd,UINT uiMsg,WPARAM wParam,LPARAM lParam)
{
switch(uiMsg)
{
case (0x0001): return (((OnCreate))(((hwnd)), (LPCREATESTRUCT)((lParam))) ? 0L : (LRESULT)-1L);
case (0x0005): return (((OnSize))(((hwnd)), (UINT)((wParam)), (int)(short)((WORD)((DWORD_PTR)((lParam)) & 0xffff)), (int)(short)((WORD)((DWORD_PTR)((lParam)) >> 16))), 0L);
case (0x0002): return (((OnDestroy))((hwnd)), 0L);
case (0x000F): return (((OnPaint))((hwnd)), 0L);
case 0x0318:
OnPrintClient(hwnd,(HDC)wParam);
return 0;
}
return DefWindowProcA(hwnd,uiMsg,wParam,lParam);
}
对应的源代码是:
LRESULT CALLBACK WndProc(HWND hwnd,UINT uiMsg,WPARAM wParam,LPARAM lParam)
{
switch(uiMsg)
{
HANDLE_MSG(hwnd,WM_CREATE,OnCreate);
HANDLE_MSG(hwnd,WM_SIZE,OnSize);
HANDLE_MSG(hwnd,WM_DESTROY,OnDestroy);
HANDLE_MSG(hwnd,WM_PAINT,OnPaint);
case WM_PRINTCLIENT:
OnPrintClient(hwnd,(HDC)wParam);
return 0;
}
return DefWindowProc(hwnd,uiMsg,wParam,lParam);
}
好了大家应该了解##的用途吧.
关于预处理到文件我还想说关于MFC的消息处理MFC消息也是有很多宏的,在头文件上有这句DECLARE_MESSAGE_MAP()
在实现文件里有类似于这样的
BEGIN_MESSAGE_MAP(CMySPYDlg, CDialog)
//{{AFX_MSG_MAP(CMySPYDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
关于具体的MFC原理大家看<<深入浅出MFC>>侯捷的,看到这些宏大家头肯定大了(如果想深入理解MFC的话),还是用预处理到文件,加个/P /EP 选项
看下生成的(.i)文件,
DECLARE_MESSAGE_MAP()展开为
protected:
private: static const AFX_MSGMAP_ENTRY _messageEntries[]; protected: static const AFX_MSGMAP messageMap; static const AFX_MSGMAP* __stdcall _GetBaseMessageMap(); virtual const AFX_MSGMAP* GetMessageMap() const;
----
BEGIN_MESSAGE_MAP(CMySPYDlg, CDialog)
//{{AFX_MSG_MAP(CMySPYDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()展开为
const AFX_MSGMAP* __stdcall CMySPYDlg::_GetBaseMessageMap() { return &CDialog::messageMap; } const AFX_MSGMAP* CMySPYDlg::GetMessageMap() const { return &CMySPYDlg::messageMap; } const AFX_MSGMAP CMySPYDlg::messageMap = { &CMySPYDlg::_GetBaseMessageMap, &CMySPYDlg::_messageEntries[0] }; const AFX_MSGMAP_ENTRY CMySPYDlg::_messageEntries[] = {
{ 0x0112, 0, 0, 0, AfxSig_vwl, (AFX_PMSG)(AFX_PMSGW)(void ( CWnd::*)(UINT, LPARAM))&OnSysCommand },
{ 0x000F, 0, 0, 0, AfxSig_vv, (AFX_PMSG)(AFX_PMSGW)(void ( CWnd::*)(void))&OnPaint },
{ 0x0037, 0, 0, 0, AfxSig_hv, (AFX_PMSG)(AFX_PMSGW)(HCURSOR ( CWnd::*)())&OnQueryDragIcon },
{ 0x0201, 0, 0, 0, AfxSig_vwp, (AFX_PMSG)(AFX_PMSGW)(void ( CWnd::*)(UINT, CPoint))&OnLButtonDown },
{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } };
虽然乱了点但是比自己慢慢展开来得快,准确.好了大家可以好好学学MFC原理了.
#include <stdio.h>
#include <process.h>
#define ABC(a,b) ABC_##a(b) //a就相当于宏里的变量
#define ABC_A(b) (b+b) //上一句a传A,或B就调用这两句
#define ABC_B(b) (b*b)
int main(int argc,char *argv[])
{
printf("%d\n",ABC(A,3)); //a=A 调用ABC_A(3) = 6
printf("%d\n",ABC(B,3)); //a=B 调用ABC_B(3) = 9
system("pause");
return 0;
}
好了关于##我所知道的就这个,关于使用,我所知道的是Windwos的消息解析器(<<Windows核心编程>>附录B),一句HANDLE_MSG简化好多问题(不过很少有人直接用SDK编程,都被MFC强奸了),大家直接看HANDLE_MSG的源代码:
/****** Message crackers ****************************************************/
#define HANDLE_MSG(hwnd, message, fn) \
case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn))
.....
#define HANDLE_WM_CREATE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (LPCREATESTRUCT)(lParam)) ? 0L : (LRESULT)-1L)
.....
就选这么点,使用的时候大家可以
HANDLE_MSG(hwnd,WM_CREATE,OnCreate);
宏会展开成什么大家应该可以根据上面例子展开.
好了在介绍个cl的选项 /P(预处理到文件) /EP(预处理到标准输出,没有 #line)有了这两个选项我们就可以将编译器(cl)的预处理文件保存到文件(*.i)(注意:加了这两个选项后编译器不好生成可执行文件,所以权当学习宏使用) VC6.0没有这个选项要手动加,如图:
VS2005就可以可视化选了,如图:
好了我们可以看看生成的文件了:
直接拖到最后可以看到这一段:
LRESULT __stdcall WndProc(HWND hwnd,UINT uiMsg,WPARAM wParam,LPARAM lParam)
{
switch(uiMsg)
{
case (0x0001): return (((OnCreate))(((hwnd)), (LPCREATESTRUCT)((lParam))) ? 0L : (LRESULT)-1L);
case (0x0005): return (((OnSize))(((hwnd)), (UINT)((wParam)), (int)(short)((WORD)((DWORD_PTR)((lParam)) & 0xffff)), (int)(short)((WORD)((DWORD_PTR)((lParam)) >> 16))), 0L);
case (0x0002): return (((OnDestroy))((hwnd)), 0L);
case (0x000F): return (((OnPaint))((hwnd)), 0L);
case 0x0318:
OnPrintClient(hwnd,(HDC)wParam);
return 0;
}
return DefWindowProcA(hwnd,uiMsg,wParam,lParam);
}
对应的源代码是:
LRESULT CALLBACK WndProc(HWND hwnd,UINT uiMsg,WPARAM wParam,LPARAM lParam)
{
switch(uiMsg)
{
HANDLE_MSG(hwnd,WM_CREATE,OnCreate);
HANDLE_MSG(hwnd,WM_SIZE,OnSize);
HANDLE_MSG(hwnd,WM_DESTROY,OnDestroy);
HANDLE_MSG(hwnd,WM_PAINT,OnPaint);
case WM_PRINTCLIENT:
OnPrintClient(hwnd,(HDC)wParam);
return 0;
}
return DefWindowProc(hwnd,uiMsg,wParam,lParam);
}
好了大家应该了解##的用途吧.
关于预处理到文件我还想说关于MFC的消息处理MFC消息也是有很多宏的,在头文件上有这句DECLARE_MESSAGE_MAP()
在实现文件里有类似于这样的
BEGIN_MESSAGE_MAP(CMySPYDlg, CDialog)
//{{AFX_MSG_MAP(CMySPYDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
关于具体的MFC原理大家看<<深入浅出MFC>>侯捷的,看到这些宏大家头肯定大了(如果想深入理解MFC的话),还是用预处理到文件,加个/P /EP 选项
看下生成的(.i)文件,
DECLARE_MESSAGE_MAP()展开为
protected:
private: static const AFX_MSGMAP_ENTRY _messageEntries[]; protected: static const AFX_MSGMAP messageMap; static const AFX_MSGMAP* __stdcall _GetBaseMessageMap(); virtual const AFX_MSGMAP* GetMessageMap() const;
----
BEGIN_MESSAGE_MAP(CMySPYDlg, CDialog)
//{{AFX_MSG_MAP(CMySPYDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()展开为
const AFX_MSGMAP* __stdcall CMySPYDlg::_GetBaseMessageMap() { return &CDialog::messageMap; } const AFX_MSGMAP* CMySPYDlg::GetMessageMap() const { return &CMySPYDlg::messageMap; } const AFX_MSGMAP CMySPYDlg::messageMap = { &CMySPYDlg::_GetBaseMessageMap, &CMySPYDlg::_messageEntries[0] }; const AFX_MSGMAP_ENTRY CMySPYDlg::_messageEntries[] = {
{ 0x0112, 0, 0, 0, AfxSig_vwl, (AFX_PMSG)(AFX_PMSGW)(void ( CWnd::*)(UINT, LPARAM))&OnSysCommand },
{ 0x000F, 0, 0, 0, AfxSig_vv, (AFX_PMSG)(AFX_PMSGW)(void ( CWnd::*)(void))&OnPaint },
{ 0x0037, 0, 0, 0, AfxSig_hv, (AFX_PMSG)(AFX_PMSGW)(HCURSOR ( CWnd::*)())&OnQueryDragIcon },
{ 0x0201, 0, 0, 0, AfxSig_vwp, (AFX_PMSG)(AFX_PMSGW)(void ( CWnd::*)(UINT, CPoint))&OnLButtonDown },
{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } };
虽然乱了点但是比自己慢慢展开来得快,准确.好了大家可以好好学学MFC原理了.
结束.
原文: