Vc. (Z)

xiaoxiao2021-03-06  49

People who have just been exposed to MFC programming are often scared by various macro definitions and preprocessing instructions generated by the MFC wizard, but preprocessing and macro definition is a powerful tool for C language. Use them to make simple source control, version control, warning, or complete some special features.

A classic example

The most classic example of using preprocessing and macro is ominous with a header file to avoid head files twice. Imagine this situation, there is a file headerfile.h it is included in HeaderFile1.h, and it is also included in HeaderFile2.h. Now there is a CPP file, IMplement.cpp contains headerfile1.h and headerfile2.h :

#include "headerfile1.h"

#include "headerfile2.h"

Assume that a global variable IGLOBAL is defined in HeaderFile.h.

IGLOBAL;

When compiling, the compiler compiles Headerfile, and it will find that IGLOBAL is defined twice, and the compilation error of the variable redifact will occur.

The traditional solution is to use #ifdef and #endif to avoid repeated compilation of the header file. In the above example, just add such lines:

#ifndef smartnose_2002_6_21_Headerfile_H

#define smartnose_2002_6_21_Headerfile_H

IGLOBAL;

#ENDIF

Carefully consider the above macro definition, it will find that after compiler compiles HeaderFile.h, smartnose_2002_6_21_headerfile_h This macro is defined, and the compilation of HeaderFile.h will skip int IGLOBAL in the future. Of course, smartnose_2002_6_21_headerfile_h This macro is arbitrarily defined, but this macro itself cannot repeat the macro defined in other files, so MFC always uses a randomly generated long-long macro in the automatically generated file, but I think this is not If necessary, I recommend adding some meaningful information, more than one author, file name, file creation time, etc., because we sometimes forget to join this information in the comment.

In VC.NET, we will not see these macros again, because a pre-processing instruction is generally used here:

#pragma overce

As long as the first instructions in the header file can guarantee that the header file is compiled once, this instruction is actually in VC6, but considers compatibility and not much using it.

Source code version control

Source code version control

When we develop multiple versions for many versions, we can help us up. Suppose we have developed a software for Windows and Linux, because of these two systems, we have to control the version of the source code. For the assignment of the memory, we can use the standard C's Malloc function on Linux, but we want to use the HeapAlloc API on Windows. The following code demonstrates this situation:

Main ()

{

..................

#ifdef _Windows_Platform

Heapalloc (5);

#ELSE

Malloc (5);

#ENDIF

..................

}

When we compile this program on a Windows platform, we only need to define _windows_platform this macro, then Heapalloc's statement can work. This will allow us to implement different versions of the code for different platforms in the same file, while maintaining a good structure of the program. In many cases, we can also use different algorithms for a method, then use macro definition to select one of them to compile one for different situations. This is the most used in the MFC application. The most obvious thing is to often exist in the file. #Ifdef _debug

........................ .some code ......... ..

#ENDIF

Such a code, these codes will play its role in the debug version of the application (DEBUG).

#Pragma instruction

In all preprocessing instructions, the # prgMA instruction may be the most complicated, its role is to set the status of the compiler or indicate that the compiler does some specific actions. Its format is generally

#Pragma para

Where parameters are parameters, look at some common parameters.

Message parameters. The Message parameter is my favorite parameter, which can output the corresponding information in the Compilation Information Output window, which is very important for the control of source code information. The method of use is:

#Pragma message ("Message Text")

When the compiler encounters this instruction, print the message text in the compilation output window.

When we define many macros in the program to control the source code version, we may have forgotten that there is no correct settings. At this time we can use this instruction to check when compiling. Suppose we want to determine if you have anywhere in the source code _X86 this macro can be used in the following method

#ifdef _x86

#Pragma message ("_ x86 macro actid!")

#ENDIF

When we define _x86 this macro, the application will display "_x86 macro actid!" In the compilation output window when compiling. We will not scratch it because of some specific macro they define.

Another PRAGMA parameter that is used is Code_SEG. Formats such as:

#pragma code_seg ([Section-Name "[," Section-Class "]])

It can set the code segment stored in the program in the program, which will be used when we develop the driver.

The last relatively commonly used is the #pragma onCE instruction above.

VC predefined macro

VC predefined macro

A type of macro in the VC is not defined by the user with a #define statement, but the compiler itself can identify them. The role of these macros is also quite large. Let us look at the first, and the most frequent use of the MFC: __ file__.

When the compiler encounters this macro, the compiler is expanded into the file name of the current compiled file. Ok, we can think that you can use it, when the app is wrong, we can report this error that the program code is in which file is in the file Test.cpp:

Try

{

Char * p = new (char [10]);

}

Catch (CEXCEPTION * E)

{

Trace ("there is an an error in file:% s / n", __ file__);

}

When the program is running, if the memory allocation has an error, then there will appear in the debug window, and the sentence, of course, we can also display this error message in other places.

If we can also record the error, it is good. Lucky is, like __file__ macro, there is a macro records the number of rows where the current code is located, this macro is __line__. With the above two macros, we can write a Assert statement similar to the VC. Below is the method #define myassert (x) /

IF (! (x)) /

MessageBox (__ file __, __ line __, null, mb_ok);

We can use it in the application, using it like using an Assert statement, when an error occurs, it will pop up a dialog box, its title and content tell us that the file and code line number occurred in our error, which makes our debugger, this is not It is very useful for projects using an Assert statement.

In addition to these two macros, there is __time__, record date ___, and record file modification time __timestamp__ macro.

Using these predefined macros, we can generate the same complete source code information whose VC can generate.

in conclusion

Open the source code of MFC and Linux, macro definitions almost occupy half of the sky, message mapping, queue operations, platform transplants, version management, and even remove the macro definition by the core module. Some files can only see macro definitions without exaggeration. So learning macro definitions, skilled use macro definitions are critical to learning C language or even VC. -------------------------------------------------- -------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------

## Connector with # 符

## The connection symbol consists of two wells, and its function is to join two substrings (TOKEN) to form a new substring in macro definitions with parameters. But it can't be the first or last substring. The so-called substring is the minimum grammatical unit that the compiler can recognize. Specific definitions have a detailed explanation in the compilation principle, but don't know how much it is. At the same time, it is worth noting that the # 符 is replacing the passing parameters as a string. Let's take a look at how they work. This is an example of MSDN.

The hypothesis has defined such a macro with parameters:

#define paster (n) printf ("token" #n "=% d", token ## n)

At the same time, a plastic variable is defined:

INT token9 = 9;

This macro is called now in the main program:

PASTER (9);

So when compiling, the above sentence is expanded to:

Printf ("token" "9" "=% D", token9);

Note that in this example, this "9" in the Paster (9) was originally stunned as a string, and the "token" is connected together, thus becomes token9. The #n is also replaced by "9".

It is conceivable that the result of the above program is to print token9 = 9 on the screen.

In the programming of ATL, we will see a paragraph in this source code:

#define imports_interface (itf) / {& IID _ ## itf, entry_is_offset, base_offset (_ITCLS, ITF)},

We often use it in this way:

......

IMPLEMENTS_INTERFACE (ICAT)

......

In fact, IID_ICAT has been defined by the ATL wizard in other places. When there is no wizard, you can use this macro as long as you follow the rules that define the IID_ to define the rules of the GUID. This skill may be rarely used in the actual development process, but ATL uses so broad, and there are many such source code, so it is quite important to understand what it is. My friend is because I don't know how the imports_interface macro is defined, and I accidentally changed the definition of IID_ICAT and busy all day. LINUX's strange circle