C/C ++ macros bring amazing tricks

Source: Internet
Author: User

Author: Kevin Lynx Source: C ++ blog

From: http://www.kuqin.com/language/20080319/4797.html

Many C ++ books advise us that C language macros are the first of all evil, but things are not as bad as we think, just like Goto. Macro
A major role is to automatically generate code for us. If the template can generate various types of code (type replacement) for us ),
In fact, macros can generate new Code (replacement and addition of symbols) on the symbols ).

You can find some macro Syntax problems on Google. Believe me, you do not know as much about macros as you think. If you
If you do not know # And #, and do not know prescan, you certainly do not know enough about macros.

I will explain some Syntax problems of macros (it seems that the syntax problem is inappropriate. macro is only related to Preprocessor and has nothing to do with semantic analysis ):

1. Macros can be defined like functions, for example:
# Define min (x, y) (x <Y? X: Y) // In fact, this macro has a bug.
However, in actual use, Min is expanded as a macro only when min () is written and must be enclosed in parentheses. Otherwise, no processing is performed.

2. If a macro requires a parameter, you can skip it. The compiler will give you a warning (the macro parameter is not enough), but this will cause an error. As described in C ++ books
The compiler (pre-processor) does not check the syntax of the macro, so you have to do more checks on your own.

3. What many programmers do not know # And ##
# The symbol directly converts a symbol to a string, for example:
# Define string (x) # x
Const char * STR = string (test_string); the content of STR is "test_string", that is, # The post-Symbol
Double quotation marks are added directly.
# The symbol is connected to two symbols to generate a new symbol (lexical level), for example:
# Define sign (x) int _ # x
Int sign (1); after the macro is expanded, it becomes: int int_1;

4. Variable Parameter macros. This is cool. It allows you to define macros similar to the following:
# Define log (format,...) printf (format, _ va_args __)
Log ("% S % d", STR, count );
_ Va_args _ is a system preset macro, which is automatically replaced with the parameter list.

5. What happens when a macro calls itself? For example:
# Define test (x) (x + test (x ))
Test (1); what will happen? To prevent unrestricted recursive expansion, the syntax stipulates that when a macro encounters itself, it stops expansion, that is
When testing (1) is expanded, another test is found during the expansion process, so the test is treated as a general symbol. Test (1)
It is expanded to 1 + test (1 ).

6. Macro parameter prescan,
When a macro parameter is placed into the macro body, the macro parameter is expanded first (for exceptions, see the following description ). When the expanded macro parameters are placed into the macro body,
The pre-processor performs a second scan on the new macro and continues to expand. For example:
# Define param (x) x
# Define addparam (x) int _ # x
Param (addparam (1 ));
Because addparam (1) is used as the macro parameter of Param, we first expand addparam (1) To int_1, and then put int_1 into Param.

The exception is that if you use # Or # For macro parameters in the param macro, the macro parameters are not expanded:
# Define param (x) # x
# Define addparam (x) int _ # x
Param (addparam (1); expands to "addparam (1 )".

Using such a rule, you can create an interesting technology: print out a macro after it is expanded, so that you can analyze the code easily:
# Define to_string (x) to_string1 (X)
# Define to_string1 (x) # x
To_string first expands all X (if X is also a macro), and then passes it to to_string1 to convert it to a string. Now you can:
Const char * STR = to_string (param (addparam (1); check the expanded Param.

7. A very important addition: as I said at the first point, if a macro like a function does not contain parentheses during use, the Preprocessor is just
Process the macro as a general symbol (that is, do not process it ).

Let's take a look at how macros help us automatically generate code. As I said, macros generate code at the symbol level. I'm analyzing boost. Function
Module, because it uses a large number of macros (macro embedding and nesting), so I did not understand the code at all. Later I found a small template library TTL
Is to develop some small components to replace some boost (this is a good reason, because boost is indeed too large ). Similarly, this library contains a function library.
The function here is the functor I mentioned earlier. The TTL. function library uses a macro to automatically generate many similar code:

# Define ttl_func_build_functor_caller (N )/
Template <typename R, ttl_tparams (n)>/
Struct functor_caller_base # N/
///...
The final purpose of this macro is to automatically generate many functor_caller_base templates by calling methods similar to ttl_func_build_functor_caller (1:
Template <typename R, typename T1> struct functor_caller_base1
Template <typename R, typename T1, typename T2> struct functor_caller_base2
Template <typename R, typename T1, typename T2, typename T3> struct functor_caller_base3
///...
Then, the core part is the macro ttl_tparams (N). It can be seen that the macro is finally generated:
Typename T1
Typename T1, typename T2
Typename T1, typename T2, typename T3
///...
We may analyze the entire process of ttl_tparams (n. The analysis macro mainly grasps some of the points mentioned above. In the following process, I suggest you flip the TTL code,
Related code files: function. HPP, macro_params.hpp, macro_repeat.hpp, macro_misc.hpp, and macro_counter.hpp.

So, here we go

The analysis process is analyzed layer by layer. For example, ttl_tparams (1 ):

# Define ttl_tparams (n) ttl_tparamsx (n, T)
=> Ttl_tparamsx (1, t)
# Define ttl_tparamsx (n, T) ttl_repeat (n, ttl_tparam, ttl_tparam_end, T)
=> Ttl_repeat (1, ttl_tparam, ttl_tparam_end, T)
# Define ttl_tparam (n, T) typename T # N,
# Define ttl_tparam_end (n, T) typename T # N
# Define ttl_repeat (n, m, L, P) ttl_append (ttl_repeat _, ttl_dec (N) (M, L, P) ttl_append (ttl_last_repeat _, n) (L, p)
Note: Although ttl_tparam and ttl_tparam_end are two macros, they are used as parameters of the ttl_repeat Macro. According to prescan rules, it seems that
These two macros are expanded and then passed to ttl_repeat. However, as I mentioned earlier, these two macros are function-like macro, which must be enclosed in brackets,
If no parentheses are added, they are not treated as macros. Therefore, when expanding ttl_repeat, it should be:
=> Ttl_append (ttl_repeat _, ttl_dec (1) (ttl_tparam, ttl_tparam_end, T) ttl_append (ttl_last_repeat _, 1 )(
Ttl_tparam_end, T)
This macro looks complicated. After careful analysis, it can be divided into two parts:
Ttl_append (ttl_repeat _, ttl_dec (1) (ttl_tparam, ttl_tparam_end, T) and
Ttl_append (ttl_last_repeat _, 1) (ttl_tparam_end, T)
First, analyze the first part:
# Define ttl_append (x, y) ttl_append1 (x, y) // expand X, Y, and then connect X and Y
# Define ttl_append1 (x, y) x # Y
# Define ttl_dec (n) ttl_append (ttl_cntdec _, n)
According to the principle of expanding parameters first, ttl_dec (1) is expanded first)
=> Ttl_append (ttl_cntdec _, 1) => ttl_cntdec_1
# Define ttl_cntdec_1 0 note that ttl_cntdec _ is not a macro and ttl_cntdec_1 is a macro.
=> 0, that is, ttl_dec (1) is expanded to 0. Return to the ttl_append part:
=> Ttl_repeat_0 (ttl_tparam, ttl_tparam_end, T)
# Define ttl_repeat_0 (M, L, P)
The macro ttl_repeat_0 is empty. Therefore, the first part of the above description is ignored, and only the second part is left:
Ttl_append (ttl_last_repeat _, 1) (ttl_tparam_end, T)
=> Ttl_last_repeat_1 (ttl_tparam_end, T) // ttl_append combines ttl_last_repeat _ and 1
# Define ttl_last_repeat_1 (m, p) m (1, P)
=> Ttl_tparam_end (1, t)
# Define ttl_tparam_end (n, T) typename T # N
=> Typename T1 is expanded.

Although we have analyzed it, it is not what we really want. We should get the author's macro programming ideas from those macros. Good use of macros
It seems to be a bit tricky, but he does make our coding more automated.

References:
Macro Syntax: http://developer.apple.com/documentation/DeveloperTools/gcc-4.0.1/cpp/Macros.html
TTL (tiny Template Library): http://tinytl.sourceforge.net/

From: http://www.cppblog.com/kevinlynx/archive/2008/03/19/44828.html

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.