The artifice of C + + macros

Source: Internet
Author: User

http://misakamm.com/blog/209

The main function of a macro is to simplify code writing and to simplify some of the code that needs to be duplicated for more elegant looks. But it's not easy to use a macro, and it's easy to have disastrous consequences. This article will introduce macro-biased but very practical skills.

The first is the most commonly used technique (http://blog.misakamm.org/p/209):

Define MACROCAT (x, y) MACROCAT1 (x, y)Define MACROCAT1 (x, y) x# #yDefine TOSTRING (s) #s

Macrocat the x and Y to the end, and ToString converts s to a string, such as printf (ToString (%s), ToString (ABCDEFG));

Then, because the macro cannot be recursive, but can do recursive simulation, we can play this way. For example, to generate an n-bit binary number and a small-to-large string (using the preceding macro):

Define BIN_0 (ARG) TOSTRING (ARG)Define BIN_1 (ARG) bin_0 (Macrocat (ARG, 0)) "," Bin_0 (Macrocat (ARG, 1))Define Bin_2 (ARG) bin_1 (Macrocat (ARG, 0)) "," Bin_1 (Macrocat (ARG, 1))Define BIN_3 (ARG) bin_2 (Macrocat (ARG, 0)) "," Bin_2 (Macrocat (ARG, 1))Define BIN_4 (ARG) bin_3 (Macrocat (ARG, 0)) "," Bin_3 (Macrocat (ARG, 1))

int main ()

{

puts(BIN_4());return 0;

}

It is important to note that, for example, Bin_2 (), the result of the actual expansion is

"0" "0" "," "0" "1" "," "1" "0" "," "1" "1"

However, C + + rules such ligatures strings, compile time will be merged into one, so you can use puts directly complete output of the results

If you want to get more bits, very simple, as long as you don't mind, the above macro copy and change the number on it.

However, such a change to change a number of numbers, more trouble, can you make it work better? For example, just change the macro name?

This time, it is necessary to use a more skillful trick: let each macro more than one parameter n, and then the front of the bin_x use Macrocat to connect it with the number, can you?

The idea is good, but the problem is that the macro itself does not have the ability to do subtraction, can only be replaced. Minus 1 How should it be achieved?

In fact, it is not difficult to see the following definition:

Define Decval_1 0Define DECVAL_2 1Define Decval_3 2Define Decval_4 3Define DECVAL_5 4Define Decval_6 5Define DECVAL_7 6Define Decval_8 7Define Decval_9 8Define DECVAL (n) decval_# #n

Well, with this tool, we can change the original macro, first take the No. 0 and 1th macro surgery:

Define BIN_0 (n, Arg) TOSTRING (ARG)Define BIN_1 (n, Arg) macrocat (Bin_, Decval (n)) (Decval (n), Macrocat (ARG, 0)) \
    "," MACROCAT(BIN_, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))

Do you have any idea what you've replaced? So, after the 2,3,4,5, just copy the definition of number 1th, change the name of the macro to solve the problem

Study Questions

The binary result generated here is a leading 0, how can I overwrite the resulting result without leading 0?

source:http://blog.misakamm.org/p/209

Using this method can be "recursive" to generate a lot of similar code, and this technique is very practical, but recursive construction is not easy, need to write the person carefully think clearly, otherwise it is easy to make mistakes, especially to pay attention to the timing of macro expansion, generally do not directly use MACROCAT1 macro, because that is probably not the result you want

After the introduction of the C99 standard (that is, the following is not compatible with BC3/TC/VC6), the macro inside a more ruthless role: variable number of parameters macro

For example, you can #define PRINTF (...) fprintf (stdout, Va_args)

Where Va_args represents all the parameters of the ' ... ' section, so that it is easy to redefine the output behavior of functions with indeterminate parameters in the library function, such as printf redirection to a file (although it can also be implemented with Freopen, but only to show that the macro can do so)

Well, the following will be a distinction between the compiler to introduce, divided into two, VC and GCC (including CLANG/OBJC), because the two of the code below the processing is not consistent, need to use a slightly different macro to achieve, at present I only encounter these two factions.

Now the purpose is this, because Va_args contains a number of parameters, how can I know how many of the parameters inside?

For example, write a macro num_params (), which is written in Num_params (Abc,a,d,e), the replacement of the results obtained if 4, can do it?

Ad time:

http://blog.misakamm.org/p/209

After the ad, come back to the wonderful show

First introduce the GCC solution:

Define PP_NARG (...) Pp_narg ( Va_args_, Pp_rseq_n ())Define Pp_narg (...) Pp_arg_n ( Va_args_)Define PP_ARG_N (\
    _1, _2, _3, _4, _5, _6, _7, _8, _9,_10,     _11,_12,_13,_14,_15,_16, N, ...) N
Define PP_RSEQ_N () \
    16,15,14,13,12,11,10,     9,8,7,6,5,4,3,2,1,0

Very beautiful ingenious and concise scheme, I think I do not have to explain more?

However, please note that this is the GCC scheme, the above code in vc8/vc9/vc2010 and so will not get the correct results, this and the VC macro processing method

Next is to give the VC solution (the following are vc2008 and vc2010)

Define bracket_l () (Define BRACKET_R ())Define PP_NARG (...) \
PP_NARG_ ( __VA_ARGS__, PP_RSEQ_N() )
Define Pp_narg_ (...) \
PP_ARG_N BRACKET_L() __VA_ARGS__ BRACKET_R()
Define PP_ARG_N (\
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, _11,_12,_13,_14,_15,_16, N,...) N
Define PP_RSEQ_N () \
16,15,14,13,12,11,10, 9,8,7,6,5,4,3,2,1,0

A special point here is the substitution of some of the parentheses.

The problem is that when pp_narg_ to Pp_arg_n to do parameter passing, if there is an explicit parenthesis, then do not expand the macro inside the calculation of the number of parameters, only directly according to the number of explicit commas to determine the number of parameters, resulting in Va_args as a parameter passed in. When you replace the parentheses with a macro, you do not have a direct parenthesis, just expand the macro, and then expand the newly constructed macro to make the parameters match.

However, GCC can not do this, GCC will expand the macro name, if found that the following symbol is not an explicit parenthesis, the preceding macro is symbolized, no longer expand. These two different characteristics let me not yet know how to write a macro to make the two can be compatible, to correctly expand the things I want.

After explaining the different points of the two compilers, the same problem is no longer explained, and two code is given at a time.

Another similar problem is that since there is an indefinite number of arguments, what if I want to do some processing on each of these parameters?

For example, implement a macro # define SPREAD (...) to make a string of things in a parameter

In the previous example, we have implemented the means of expanding the indefinite parameters, and now we are going to try a recursive descent-type expansion (GCC version):

Define SPREAD0 (ARG) #argDefine SPREAD1 (ARG, ...) SPREAD0 (ARG)Define SPREAD2 (ARG, ...) SPREAD0 (ARG) SPREAD1 ( Va_args,)Define SPREAD3 (ARG, ...) SPREAD0 (ARG) SPREAD2 ( Va_args,)Define SPREAD4 (ARG, ...) SPREAD0 (ARG) SPREAD3 ( Va_args,)Define SPREAD5 (ARG, ...) SPREAD0 (ARG) SPREAD4 ( Va_args,)Define SPREAD6 (ARG, ...) SPREAD0 (ARG) SPREAD5 ( Va_args,)Define SPREAD7 (ARG, ...) SPREAD0 (ARG) SPREAD6 ( Va_args,)Define SPREAD8 (ARG, ...) SPREAD0 (ARG) SPREAD7 ( Va_args,)Define SPREAD9 (ARG, ...) SPREAD0 (ARG) SPREAD8 ( Va_args,)Define SPREAD (...) SPREAD9 ( Va_args)

Here, each entry layer, from the Va_args to disassemble a first parameter out, the remaining parameters to the next layer

Here is a detail that is Va_args behind a comma, meaning to fill an empty parameter, to avoid the following parameters are not enough

Then you can use puts (SPREAD (1, 2, 3, 4)) to test

And, of course, use the same approach as in the previous article (GCC version):

Define SPREAD0 (ARG) #argDefine SPREAD1 (n, ARG, ...) SPREAD0 (ARG)Define SPREAD2 (n, ARG, ...) SPREAD0 (ARG) macrocat (SPREAD, Decval (n)) (Decval (n), Va_args, )Define SPREAD3 (n, ARG, ...) SPREAD0 (ARG) macrocat (SPREAD, Decval (n)) (Decval (n), Va_args, )Define SPREAD4 (n, ARG, ...) SPREAD0 (ARG) macrocat (SPREAD, Decval (n)) (Decval (n), Va_args, )Define SPREAD5 (n, ARG, ...) SPREAD0 (ARG) macrocat (SPREAD, Decval (n)) (Decval (n), Va_args, )Define SPREAD6 (n, ARG, ...) SPREAD0 (ARG) macrocat (SPREAD, Decval (n)) (Decval (n), Va_args, )Define SPREAD7 (n, ARG, ...) SPREAD0 (ARG) macrocat (SPREAD, Decval (n)) (Decval (n), Va_args, )Define SPREAD8 (n, ARG, ...) SPREAD0 (ARG) macrocat (SPREAD, Decval (n)) (Decval (n), Va_args, )Define SPREAD9 (n, ARG, ...) SPREAD0 (ARG) macrocat (SPREAD, Decval (n)) (Decval (n), Va_args, )Define SPREAD (...) SPREAD9 (9, Va_args)

VC Version:

pragma warning (disable:4003)//Removal warningDefine SPREAD0 (ARG) #argDefine SPREAD1 (n, ARG, ...) SPREAD0 (ARG)Define SPREAD2 (n, ARG, ...) SPREAD0 (ARG) macrocat (SPREAD, Decval (n)) bracket_l () Decval (n), Va_args, Bracket_r ()Define SPREAD3 (n, ARG, ...) SPREAD0 (ARG) macrocat (SPREAD, Decval (n)) bracket_l () Decval (n), Va_args, Bracket_r ()Define SPREAD4 (n, ARG, ...) SPREAD0 (ARG) macrocat (SPREAD, Decval (n)) bracket_l () Decval (n), Va_args, Bracket_r ()Define SPREAD5 (n, ARG, ...) SPREAD0 (ARG) macrocat (SPREAD, Decval (n)) bracket_l () Decval (n), Va_args, Bracket_r ()Define SPREAD6 (n, ARG, ...) SPREAD0 (ARG) macrocat (SPREAD, Decval (n)) bracket_l () Decval (n), Va_args, Bracket_r ()Define SPREAD7 (n, ARG, ...) SPREAD0 (ARG) macrocat (SPREAD, Decval (n)) bracket_l () Decval (n), Va_args, Bracket_r ()Define SPREAD8 (n, ARG, ...) SPREAD0 (ARG) macrocat (SPREAD, Decval (n)) bracket_l () Decval (n), Va_args, Bracket_r ()Define SPREAD9 (n, ARG, ...) SPREAD0 (ARG) macrocat (SPREAD, Decval (n)) bracket_l () Decval (n), Va_args, Bracket_r ()Define SPREAD (...) SPREAD9 bracket_l () 9, Va_args, Bracket_r ()

The above is only a vague way to expand, because the number of parameters do not know, the following will be encountered when the macro parameter is empty, the VC compiler gave a warning

If the previous skill, is to analyze the number of indefinite parameters of the macro, and this combination, will produce greater power, we can achieve accurate expansion, is in the definition of spread macro, there are 9 of places using macro Pp_narg (Va_args) to replace, so the comma behind the Va_args can be removed, you can simplify some code, and you can avoid the expansion of unwanted characters that you don't want to appear.

Test Exam 1:

Define a macro # define printf so that it can put printf (str, a, b, c); replace it with Std::cout?a?b?c?std::endl;

Parameter number is indeterminate, do not consider STR content, but assume no more than 10 parameters

http://blog.misakamm.org/p/209

The power of the macro is more than this, when the macro and C + + template programming together, the real terrible is coming ...

Test Exam 2:

Before c++0x, the template does not have parameters, so when you need multiple parameters, you have to manually solve, or smart people, using templates to generate multi-parameter template code. Try to do this and see where the difficulty with the previous question increases. For example, generate a template function named Sum, can accept 1–10 parameters, return the results of the addition of these parameters

Article comes with:

The first questions refer to the answer:

Define BINARY_E0 (n, Arg) TOSTRING (ARG)Define BINARY_E1 (n, Arg) macrocat (binary_e, Decval (n)) (Decval (n), Macrocat (ARG, 0)) \
"," MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 1) )
Define BINARY_E2 (n, Arg) macrocat (binary_e, Decval (n)) (Decval (n), Macrocat (ARG, 0)) \
"," MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 1) )
Define BINARY_E3 (n, Arg) macrocat (binary_e, Decval (n)) (Decval (n), Macrocat (ARG, 0)) \
"," MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 1) )
Define BINARY_E4 (n, Arg) macrocat (binary_e, Decval (n)) (Decval (n), Macrocat (ARG, 0)) \
"," MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 1) )
Define BINARY_E5 (n, Arg) macrocat (binary_e, Decval (n)) (Decval (n), Macrocat (ARG, 0)) \
"," MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 1) )
Define BINARY_E6 (n, Arg) macrocat (binary_e, Decval (n)) (Decval (n), Macrocat (ARG, 0)) \
"," MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 1) )
Define BINARY_E7 (n, Arg) macrocat (binary_e, Decval (n)) (Decval (n), Macrocat (ARG, 0)) \
"," MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 1) )
Define BINARY_E8 (n, Arg) macrocat (binary_e, Decval (n)) (Decval (n), Macrocat (ARG, 0)) \
"," MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 1) )
Define Binary_enum (N) macrocat (Binary_e, N) (n,)Define BIN_0 (n, Arg) TOSTRING (ARG)Define BIN_1 (n, Arg) macrocat (Bin_, Decval (n)) (Decval (n), arg) \
    "," MACROCAT(BINARY_E, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
Define BIN_2 (n, Arg) macrocat (Bin_, Decval (n)) (Decval (n), arg) \
    "," MACROCAT(BINARY_E, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
Define BIN_3 (n, Arg) macrocat (Bin_, Decval (n)) (Decval (n), arg) \
    "," MACROCAT(BINARY_E, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
Define BIN_4 (n, Arg) macrocat (Bin_, Decval (n)) (Decval (n), arg) \
    "," MACROCAT(BINARY_E, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
Define BIN_5 (n, Arg) macrocat (Bin_, Decval (n)) (Decval (n), arg) \
    "," MACROCAT(BINARY_E, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
Define BIN_6 (n, Arg) macrocat (Bin_, Decval (n)) (Decval (n), arg) \
    "," MACROCAT(BINARY_E, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
Define BIN_7 (n, Arg) macrocat (Bin_, Decval (n)) (Decval (n), arg) \
    "," MACROCAT(BINARY_E, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
Define BIN_8 (n, Arg) macrocat (Bin_, Decval (n)) (Decval (n), arg) \
    "," MACROCAT(BINARY_E, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
Define BIN_ENUM (N) "0" Macrocat (bin_, N) (n,)

Test code: Puts (Bin_enum (8));

Test questions do not provide answers.

Related articles

    1. Syntax highlighting test
    2. Try the MMX optimization AlphaBlend again
    3. The free X-Pain is a program that has written a C + + source file to remove the comment code
    4. The small art of C-language circulation
    5. Delegate Mode C + + preliminary implementation of the bad code a copy ... Bay stretched out
    6. Another algorithm for enumerating all combinations with bit operations
    7. [Original] 88 lines of code to implement Tetris game (including explanation)
    8. Alternative Shebinski (Sierpinski) fractal triangle output Program

The artifice of C + + macros

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.