C ++ macro Summary

Source: Internet
Author: User

Some people regard macros as the beasts of the flood, and even require them to be completely abandoned from C/C ++. Some people regard macros as the supreme template, which is widely used in logic code. I personally think this is a matter of opinion and wisdom. It is unnecessary to abandon it. Let's look at some classic applications of macro in MFC and ATL, you will find that if you do not use macros to Implement Message ing and object ing, it will make "hard" Programmers spend more valuable time. Of course, it cannot be abused, especially if you try not to use it in the logic code. If there is a logic problem in the macro, you will find that the programmer is really "hard.

In fact, many people may be afraid of macros due to the following simple macro implementation:

# Define sum (x, y) x + y

It looks correct, but when you use sum (3, 4) * sum (2, 5) in this way, you will find that the result is not as expected 49, it's a strange 16. The real macro only performs simple replacement, instead of calculating the parameters like the function and calling the return result. The formula above is sum (3, 4) * sum (2, 5) actually, it will be replaced with 3 + 4*2 + 5. Now we know why the result is 16, so we should implement this:

# Define sum (x, y) (x + y)

Wrap the whole with parentheses. It seems correct. But if sum (3 | 4, 4) is called like this, will the result be 5? Er, no. The result is 1. What's wrong? Let's take a look at the expanded result 3 | 4 + 4, because the addition calculation level is higher than 3 | 4 + 4 = 3 | 8 = 1, we have to include the following parameters:

# Define sum (x, y) (x) + (y ))

After some failed and failed attempts, we finally got a correct version of the two numbers sum.

From the above example, I think you should be inspired and can see some important points to note when writing a macro. However, the topic we will discuss today is the other few macros that may not be used much but are useful.

 

1. How can I get the offset of a field in the struct through a simple macro?

You can make the following definitions:

# Define fieldoffset (type, field) (unsigned INT) & (type *) 0)-> field)

Explanation: forcibly convert 0 to a type pointer, and then access the field. Note that it is not a real access, but an address is obtained for it. The offset is obtained after the base address 0 of the structure is subtracted from the address, because the base address is 0, it is omitted.

The number of bytes occupied by field in a struct can also be defined:

# Define fieldsize (type, field) sizeof (type *) 0)-> field)

 

2. #, ###and # @ usage

# Convert a macro parameter to a string (that is, double quotation marks are added to the parameter)

# Simple connection of macro parameters

# @ Convert a macro parameter to a character (that is, enclose the parameter with single quotation marks)

# Define tostring (s) # s

# Define tochar (s) # @ s

# Define tokenconn (S, T) s # T

In addition, for # @, if you call tochar (ABCD) in this way, 'D' will be returned, but if tochar (ABCDE), a compilation error will occur, it seems that this has something to do with vs's macro processor, although it is very strange to use it.

More importantly, if the map macro parameters #, # @, or # Used in macro definition are not displayed as expected, how can this problem be solved? Generally, if there is another macro in the macro parameter, It will be replaced recursively:

# Define C 7

# Define B C

# Define a B

# Define sum (x, y) (x) + (y ))

Then we call int x = sum (A, A) in this way; the compilation is normal, and the final value of X is 14. The replacement process is as follows:

Sum (A, A) => (a) + (A) => (B) + (B) => (c) + (c )) => (7) + (7 ))

However, if the following definition is available:

# Define D 12

# Define tostring (s) # s

# Define tokenconn (S, T) s # T

Then, the result of tostring (d) is "D", and the result of tokenconn (D, D) is dd. If no DD identifier is defined, an error is returned during compilation. The reason is that macro replacement is hierarchical. The outermost layer is replaced first, and then the parameter is replaced, these three special symbols have the function of changing the meaning of macro parameters (changing macro parameters to characters, strings or different tokens), so there is no multi-level expansion.

This will bring about a problem, that is, I need to use these three special Identifiers (#, # @ or #), and I need to expand the macro parameters. What should I do, I have seen such a requirement on km before. Let's first look at a common macro:

# Pragma message ("messageinfo: No impl, todo... ")

I often use this macro to insert it into the code to mark the features I have not implemented or the areas that need to be improved later. The benefit of this macro is that during compilation, the information you wrote in the message is displayed in the compilation information output window. This prevents you from forgetting what is not implemented when writing code to the end. However, the method I use is very primitive. If you need to implement a function, I will search for the information in the message globally and then find the location, later, I saw a similar requirement on KM. I can use the functions provided by IDE to directly locate the macro writing. If an error is reported during compilation, you will see the output similar to the following:

1> F: \ e \ projects \ tu_func \ tu_func.cpp (124): Error c2065: 'dd': Undeclared identifier

At this point, if you double-click this line, the code window will jump to the place where compilation errors occur. What we need to do is to simulate such an output, using two defined macros _ file _ and _ line __, I will not talk about these two macros. My first simulated version is as follows:

# Define tostring (s) # s

# Define magictipsmsg (MSG) message (_ file _ "(" tostring (_ line _) "):" # MSG)

The results were miserable and failed to meet expectations:

1> F: \ e \ projects \ tu_func \ tu_func.cpp (_ line _): There is need to implement

Apparently, the macro parameter mentioned above is not expanded. Is it swollen? In fact, the solution to this problem is not very complicated. Just add a stepping stone macro in the middle, the purpose of adding this stepping stone macro is to expand all macro parameters in this stepping stone macro layer, so the final String Conversion macro (tostring) you can get the correct macro parameters.

# Define tostring (s) # s

# DEFINE _ tostring (s)

# Define magictipsmsg (MSG) message (_ file _ "(" _ tostring (_ line _) "):" # MSG)

Now the output in the compilation window is correct:

(1) F: \ e \ projects \ tu_func \ tu_func.cpp (121): There is need to implement

 

3. Some predefined macros

_ Line __

_ File __

_ Date __

_ Time __

_ Cplusplu

Whether all the above macros are supported depends on the specific implementation of the compiler. _ Line _ indicates the number of rows of the current file where the macro is located, __file _ indicates the full path name of the current file, __date _ macro command contains a string in the form of month/day/year, indicating the date when the source file is compiled. The time when the source code is compiled into the target code is included in _ time _ as a string. Try it for yourself.

When compiling a C ++ program, the compiler automatically defines a preprocessing name__ cplusplus. What should I do if I want to know whether this macro is define? You can perform a check similar to the following:

# Ifdef _ cplusplus

# Pragma message ("_ cplusplus definded ")

# Endif

 

4. Use # pragma to export DLL Functions

Generally, we use the module definition file (. def). In fact, VC provides an extension method, using _ declspec (dllexport) to export a function:

Int _ declspec (dllexport) add (int A, int B)

The exported function is named "? Add @ yahhh @ Z "if we want to perform DLL Dynamic Links, the name of the export function above will be a bit too boring. Once the return value or parameter type of the function is modified, the function name must also be modified. We want to export the function name as "add ". There are at least two methods: one is to use the def file for export, and the other is to add the extern "C" at the beginning of the function declaration ":

Extern "C" int _ declspec (dllexport) add (int A, int B)

However, we will discuss another preprocessing macro provided by VC to solve this problem today, as follows:

# Pragma comment (linker, "/export: Add =? Add @ yahhh @ Z ")

In this case, it will actually export? Add @ yahhh @ Z and add functions, but the function entry points are the same. In fact, this macro is more powerful than that, and its format is as follows (msdn: http://msdn.microsoft.com/en-us/library/hyx1zcd3 (V = vs.80). aspx ):

/Export: entryname [, @ ordinal [, noname] [, Data]

Note: @ ordinal is used to specify the order. noname indicates that only the function is exported as the serial number, and the data keyword specifies that the export item is a data item. For example:

# Pragma comment (linker, "/export: Add =? Add @ yahhh @ Z, @ 2, noname ")

Is to export the Add function without any name and set the order to 2.

Therefore, if you want to specify the export sequence, or export the function as a sequence number without a function name, this can be achieved, previously, I discussed with my colleagues how to export a function without a name (many system DLL export tables do not have the name of the function to be exported). This preprocessing macro can be used to solve this problem.

Another problem is how to dynamically link the unsung export function itself (using the following method, assuming that the export order is 2, this unsung export not only increases the mystery, but also has an unexpected usage ):

Typedef int (* pfunadd) (INT, INT );

Hinstance hins = loadlibrary (text ("dllname. dll "));

Pfunadd pfnadd = (pfunadd) getprocaddress (hins, makeintresource (2 ));

Int c = pfnadd (1, 2 );

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.