Address: http://hi.baidu.com/joyeep/blog/item/2ad5f662e00f41dce7113a37.html
Low-level C ++ProgramOne of the members' favorite words is: C macro, the first of all evil, and the wrong beginning should be abandoned.
Example 1: Use a C macro to writeCodeMore concise this code is familiar to anyone who writes network programs. It is the implementation of mbuf in net/3.
Struct mbuf {struct m_hdr mhdr; Union {struct pkthdr mh_pkthdr;/* m_pkthdr Set */Union {struct m_ext mh_ext;/* m_ext Set */Char mh_databuf [mhlen];} mh_dat;} MH; char m_databuf [mlen];/*! M_pkther ,! M_ext */} m_dat ;};
The above code, if I want to access the mh_databuf at the innermost layer, then I have to write m_dat.mh.mh_dat.mh_databuf; is it very long and hard to write? This code is unknown. In fact, for mh_pkthdr, mh_ext, and mh_databuf, although they are not at a structural level, if we stand out from mbuf, they are all attributes of mbuf, it can be squashed to a plane. Therefore, the source code contains a set of macros:
# Define m_next m_hdr.mh_next # define m_len m_hdr.mh_len # define m_data m_hdr.mh_data ...... # define m_pkthdr extension # define m_pktdat extension ......
is it very refined to write code like this!
Example 2: Use a C macro, this is a good example of cross-platform and compiler implementation. just copy the source code from the VC library at will.
# ifndef _ crtapi1 # If _ msc_ver> = 800 & _ m_ix86> = 300 # DEFINE _ crtapi1 _ cdecl # else/* _ msc_ver> = 800 &&_ m_ix86> = 300 */# DEFINE _ crtapi1 # endif/* _ msc_ver> = 800 & _ m_ix86> = 300 */# endif/* _ crtapi1 */# ifndef _ size_t_definedtypedef unsigned int size_t; # DEFINE _ size_t_defined # endif/* _ size_t_defined */# ifndef _ Mac # ifndef _ wchar_t_definedtypedef unsigned short wchar_t; # DEFINE _ wchar_t_defined # endif/* _ wchar_t_defined */# endif/* _ Mac */# ifndef _ nlscmp_defined # DEFINE _ nlscmperror 2147483647/* Currently = int_max */# DEFINE _ nlscmp_defined # endif/* _ nlscmp_defined */
How can we replace these Indicator Macros? If you really don't have these macros, it will be more difficult to implement them.
Example 3: The use of C macro to automatically generate code is also very good, but in view of the fact that many friends do not need a lot of compilers and do not do embedded development, Let me give an example of win platform. We know that MFC implements message ing for Windows, such:
On_command (idm_about, onabout) on_command (idm_filenew, onfilenew)
How does it implement the association between idm_about and onabout? This requires several macros.
# Define declare_message_map () \ private: \ static const aggregate _ messageentries []; \ protected: \ static afx_data const afx_msgmap messagemap; \ virtual const afx_msgmap * getmessagemap () const; \ # define attributes (theclass, baseclass) \ const attributes * theclass: getmessagemap () const \ {return & theclass: messagemap;} \ afx_comdat afx_datadef const limit theclass :: messagemap =\{ & baseclass: messagemap, & theclass: _ messageentries [0]}; \ afx_comdat const afx_msgmap_entry theclass :: _ messageentries [] =\{\# define on_command (ID, memberfxn) \ {wm_command, 0, (Word) ID, (Word) ID, afxsig_vv, (afx_pmsg) memberfxn }, # define end_message_map () \ {0, 0, 0, 0, afxsig_end, (afx_pmsg) 0 }\}\# define declare_message_map () \ private: \ static const aggregate _ messageentries []; \ protected: \ static afx_data const afx_msgmap messagemap; \ virtual const afx_msgmap * getmessagemap () const; \ # define aggregate (theclass, baseclass) \ const attributes * theclass: getmessagemap () const \ {return & theclass: messagemap;} \ afx_comdat afx_datadef const inclutheclass: messagemap =\{ & baseclass: messagemap, & theclass: _ messageentries [0]}; \ afx_comdat const inclutheclass: _ messageentries [] =\{\# define on_command (ID, memberfxn) \ {wm_command, 0, (Word) ID, (Word) ID, afxsig_vv, (afx_pmsg) memberfxn}, # define end_message_map () \ {0, 0, 0, 0, afxsig_end, (afx_pmsg) 0 }\};\
Hey, there are just a few macros to construct a message array.
Example 4: I have been talking about it for a long time with the spark of C macro and wise thinking. Let's take a look at how foreigners use macros. This example is taken from expert C programming. A small bitwise pattern is used to map an icon or graph (glyph) to an image generated on the screen. One digit represents a pixel in the image. If a single bit is set, the pixel it represents is "bright. If a single bit is cleared, the pixels it represents are "dark. Therefore, a series of integer values can be used for image encoding. Tools like iconedit are used for plotting. They output an ASCII file containing a series of integer numbers that can be included by a window program. The problem is that the icon in the program is only a string of hexadecimal numbers. In C, a typical 16x16 black/white image may be as follows:
Static unsigned short stopwatch [] = {0x07c6, 0x1ff7, 0x383b, 0x600c, 0x600c, 0xc006, 0xc006, 0xdf06, 0xc106, 0xc106, 0x610c, primary, 0x3838, primary, 0xc0, 0x0000 };
As we can see, these C-language constants do not provide any clue about the actual image. Here is an amazing # define-defined elegant set that allows programs to create constants to make them look like images on the screen.
# Define x) * 2 + 1 # DEFINE _) * 2 # define s (0/* for building glyphs 16 bits wide */
After they are defined, the program will automatically create their hexadecimal mode as long as they draw the required icons or graphics. Using these macro definitions, the self-describing capability of the program is greatly enhanced. The above example can be changed:
static unsigned short stopwatch [] = {S _ x _, S _ x, S _ x, S _ x _, S _ x __, S x _, S x _, S x _, S x _, S x _, S _ x __, S _ x _, S _ x ___, S _ x _, S _ x ______, S _};
Obviously, it means more obvious than the previous code. The standard C language has octal, decimal, and hexadecimal constants, but there is no binary constant. Otherwise, it is a simpler method for drawing the image mode.
If you capture the top-right corner of the book and see this page oblique, you may guess that this is a small stopwatch image named "cursor busy" for the popular window system. I learned this technique from Usenet Comp. Lang. C News group a few years ago.
Do not forget to clear these macro definitions after the drawing is complete. Otherwise, this may cause unpredictable consequences for your subsequent code.
The water can carry the boat, but also the boat, grasp the double-edged sword in your hands, let it serve you well, don't cut your hand. :)
End