[Go to]c++ application file compilation process

Source: Internet
Author: User

Original address

This is the compilation process of C + + files and the compiling process of the template;

One: the general C + + application compilation process.
Generally speaking, the compilation process of a C + + application is divided into three phases. Templates are the same.

    1. Expand the Include file in the CPP file.
    2. Compiles each CPP file into a corresponding obj file.
    3. Connect the obj file as an EXE file (or other library file).

The following sections describe each of these phases.
The deployment of the 1.include file.
The deployment of the include file is a straightforward process, except that the code contained in the include file is copied to the CPP file (or other header file) that contains the file. The expanded CPP file becomes a separate compilation unit. In some articles I saw that the. h file and the. cpp file are treated as a compilation unit, and I think there is a problem with that understanding. As for the reasons, take a look at the following few points of attention.
1): the. h file that is not contained by any other CPP file or header file will not be compiled. And will not eventually become part of the application. Let's look at a simple example:

1 ==========test.h file ==========
2//Note that there is no semicolon behind it. That is, if you compile, this will produce an error.
3 void foo ()

Add a test.h file to your application as shown above. However, do not include the file in any of the other files. After compiling the C + + project you will find that the above code error is not reported. This indicates that the. h file itself is not a compilation unit. Only after the include statement is eventually included in a. cpp file will it become a compilation unit.

2): There is a possibility that a CPP file directly or indirectly includes multiple times the same. h file. Here's a situation like this:

1//===========test.h============
2//define a variable
3 int i;
4
5//===========test1.h===========
6//contains the Test.h file
7 #include "test.h"
8
9//===========main.cpp=========
10//This includes both Test.h and Test1.h,
11//means that two variables I are defined at the same time.
12//Compilation error will occur.
#include "stdafx.h"
#include "test.h"
#include "Test1.h"
16
+ void foo ();
void Foo ();
19
int _tmain (int argc, _tchar* argv[])
21 {
return 0;
23}

When the above code expands, it is equivalent to defining two variable I in main.cpp at the same time. Therefore, a compilation error occurs. The workaround is to use #ifndef or #pragma once macros so that test.h can be included only once in main.cpp. For #ifndef and #pragma once please refer here.

3): It is also important to note that the Include files are expanded into CPP files in the order in which they are defined. For this, take a look at the following example.

1//===========test.h============
2//Declare a function. Note that there is no semicolon behind.
3 void foo ()
4
5//===========test1.h===========
6//write only a semicolon.
7;
8
9//===========main.cpp=========
10//Note that the header files are included in the order of Test.h and Test1.h.
#include "stdafx.h"
#include "test.h"
#include "Test1.h"
14
int _tmain (int argc, _tchar* argv[])
16 {
0;
18}

If you look at the above code separately, a semicolon is required after test.h to compile the pass. The semicolon, defined in Test1.h, is exactly the semicolon that test.h the poor back. Therefore, an order definition such as Ann can be compiled and passed normally after main.cpp. Although this is not recommended in actual projects, this example can explain a lot about what the file contains.
Some people may have seen it, although a function was declared in the example above, but it was not implemented and could still be compiled. This is the content of the CPP file when it was compiled.

Compilation and linking of 2.CPP files.
As we all know, C + + compilation is actually divided into two stages of compiling and linking, because these two phases are closely related. So put it together to illustrate. At compile time, the compiler generates an obj file for each CPP file. The obj file has the pe[portable executable, the Windows executable file format, and itself contains the binary code, but it is not necessarily able to execute because there is no guarantee that the main function must be in it. When all CPP files are compiled, the obj file will be linked to an EXE file (or other form of library) as needed. Look at the following code:

1//============test.h===============
2//Declare a function.
3 void foo ();
4
5//============test.cpp=============
6 #include "stdafx.h"
7 #include <iostream>
8 #include "test.h"
9
10//Implement the functions defined in test.h.
one void foo ()
12 {
std::cout<< "foo function in test have been called." <<std::endl;
14}
15
//============main.cpp============
#include "stdafx.h"
#include "test.h"
19
int _tmain (int argc, _tchar* argv[])
21 {
$ foo ();
23
return 0;
25}

The

notes that 22 rows are called on the Foo function. The actual operation of the above code is that the compiler first generated an obj for each CPP file, here is Test.obj and main.obj (there is also a stdafx.obj, which is due to the use of the VS editor). But here's a question, although test.h is visible to Main.cpp (Main.cpp contains test.h), but test.cpp is not visible to main.cpp, then how does main.cpp find the implementation of the Foo function? In fact, when compiling the main.cpp file separately, the compiler does not first focus on whether the Foo function has been implemented or where it is implemented. It just sees it as an external link type and thinks that the implementation of the Foo function should be in a different obj file. When you call Foo in line 22, the compiler just uses an address jump, which is something like jumping 0x23423. But because I don't know where Foo is, it just fills in a fake address at the back of the jump (what exactly should be the master's advice). Then continue compiling the following code. When all CPP files are executed, enter the link stage. Because. obj and. exe are in the same format, there is a symbol import table and a symbol export table in such a file [import table and Export tables] where all symbols are associated with their addresses. In this way, the connector simply looks for the symbol in the Test.obj's symbol export table foo[the address of C + + to Foo Mapping], and then does some offset processing [because the two. obj files are merged, of course the address will be offset, this connector is clear] Writes the symbol in Main.obj to the Entry table that is the one that Foo occupies. So foo can be successfully executed.

Briefly speaking, when compiling main.cpp, the compiler does not know the implementation of F, all when it encounters a call to it just gives an indication that the connector should look for the implementation of F for it. This means that there is no line of binary code for f in Main.obj. When compiling test.cpp, the compiler found the implementation of F. The implementation of Foo [binary code] appears in the Test.obj. When connected, the connector finds the address of the implementation code [binary] of foo in test.obj [Export table by symbol]. Then change the pending jump XXX address in main.obj to the actual address of Foo.

Now make a hypothesis that the implementation of Foo () does not really exist. Let's look at the following code:

1 #include "stdafx.h"
2//#include "test.h"
3
4 void foo ();
5
6 int _tmain (int argc, _tchar* argv[])
7 {
8 foo ();
9
return 0;
11}

Notice the above code, we commented out the # include "Test.h" and re-declared a Foo function. Of course, you can also use function declarations directly in test.h. The above code is not implemented because of a function. According to our analysis above, the compiler does not report an error when it finds the call to Foo (), but expects the connector to find the implementation of Foo in the other obj files. However, the connector was eventually not found. A link error is reported.
Link: did not find E:\CPP\CPPTemplate\Debug\CPPTemplate.exe or the previous incremental link did not generate it;

Let's look at one of the following examples:

1 #include "stdafx.h"
2//#include "test.h"
3
4 void foo ();
5
6 int _tmain (int argc, _tchar* argv[])
7 {
8//foo ();
9
return 0;
11}

There is only Foo's declaration, and we have removed the original Foo's call. The above code can be compiled and passed. The reason is that because the Foo function is not called, Main.cpp does not really look for the implementation of Foo (Main.obj internal or main.obj outside), the compiler will not care if Foo is already implemented.


Second: the template compilation process.
After understanding the C + + program compilation process, then look at the template compilation process. As you know, templates need to be instantiated by template parameters into a specific class or function to use. However, the invocation of a class template member function and a very important feature is that member functions are initialized only when they are called. Because of this feature, the code for class templates cannot be organized in the same way as regular C + + classes. Let's look at the following code:

1//=========testtemplate.h=============
2 Template<typename t>
3 Class myclass{
4 Public:
5 void Printvalue (T value);
6};
7
8//=========testtemplate.cpp===========
9 #include "stdafx.h"
Ten #include "testTemplate.h"
11
Template<typename t>
void Myclass<t>::p rintvalue (T value)
14 {
15//
16}

Here is the file content for main.cpp:

1 #include <iostream>
2 #include "testTemplate.h"
3
4 int Main ()
5 {
6//1: Instantiate a class template.
7//Myclass<int> MyClass;
8
9//2: Call the member function of the class template.
//Myclass.printvalue (2);
11
Std::cout << "Hello world!" << Std::endl;
return 0;
14}

Notice the two lines of code that are commented out. We'll follow the steps to explain the template's compilation process.
1): We remove the TestTemplate.cpp file from the project, that is, delete the definition of testTemplate.cpp. Then directly compile the above file, can compile through. This means that the compiler did not check the implementation of the template class when compiling the main.cpp file after expanding testTemplate.h. It just remembers having such a template declaration. Because there is no member function to invoke the template, the compiler link stage does not find the implementation code for the class template in another obj file. So there's no problem with the code above.

2): Remove the comment symbol from line 7th in the main.cpp file. That is, the instantiation code of the class template is added. In compiling the project, you will find that you can also compile the pass. Recall this process, testTemplate.h is expanded, that is, Main.cpp in the compilation is able to find the myclass<t> statement. Then, when compiling line 7th, a class template can be instantiated normally. Note: The member functions of the class template are instantiated only when they are called. Therefore, because there is no call to the class template member function, the compiler does not look for the implementation code of the class template. So, the above function can be compiled through.

3): Remove the code comment symbol from line 10th above. The call to the class template member function is added. This time, the compiler will prompt a link error. The implementation of the printvalue could not be found. The truth and the above only function declaration, no function implementation is the same. That is, the compiler found a call to Myclass.printvalue when compiling main.cpp line 10th, when it could not find a specific implementation within the current file, so it would make a tag and wait for the linker to find the function implementation in the other obj files. Similarly, the connector could not find an obj file that includes myclass<t>::P Rintvalue declaration. Therefore, the report is linked incorrectly.

4): Since the TestTemplate.cpp file cannot be found, we will include the TestTemplate.cpp file in the project. Compile again, in VS will prompt a link error, say cannot find external type _thiscall myclass<int>::P rintvalue (int). Perhaps you will find it strange that we have included the TestTemplate.cpp file in the project. Consider a question first, we said that the compilation of a template is actually a process of instantiation, and it does not compile to produce binary code. In addition, the template member function is initialized only when it is called. In the TestTemplate.cpp file, because the TestTemplate.h header file is included, this is a standalone class template that can be compiled. However, the compiler did not instantiate the Printvalue member when compiling the TestTemplate.cpp file because no member functions were called. Perhaps you would say that we called the Printvalue function in main.cpp. But know that TestTemplate.cpp and Main.cpp are two separate compilation units, and they don't know each other's behavior. As a result, testTemplate.cpp actually compiles only the contents of the testTemplate.h, that is, the template is declared again, and there is no instantiation of the Printvalue member. Therefore, the target function is not found when Main.cpp discovers that a Printvalue member is needed and finds it in Testtemplate.obj. thereby issuing a link error.

5): This shows that the template code cannot be organized in accordance with the regular C + + code. It is important to ensure that the template's function can be instantiated by the template code when it is compiled. There are a lot of articles on the internet about this. Basically, the template is compiled into include compilation and separate compilation. In fact, whether it is a compilation or a separate compilation, is for a goal: so that the template can be instantiated to find the corresponding template implementation code. You can refer to this article.


Finally, make a small summary. The compilation of C + + applications typically goes through the three stages of a link to the build CPP file, expand header file. If an external type is required at compile time, the compiler will make a token for the connector to handle. Connector if the required external type is not found, a link error occurs. For templates, individual template code cannot be compiled correctly and requires an instantiation to produce a template instance before it can be compiled. Therefore, you cannot send a member function that you wish to link a template to, and you must ensure that the template code is visible where the template is instantiated.

[Go to]c++ application file compilation process

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.