Library and code reuse
1. Static library vs dynamic library
Advantages and disadvantages of static databases
Advantages and problems of dynamic libraries
2. Static C/C ++ Runtime Library vs dynamic C/C ++ Runtime Library & manifest
3. Dynamic library interface design
Library and code reuse
For languages like C and C ++, libraries are an important means to extend the language functions. For projects, code libraries are used to save development time and reduce costs, project module division is a necessary tool to facilitate collaboration among multiple people and avoid repetitive work by reusing existing code. To develop a project of a relatively large scale, there is always a lot of trade-offs in terms of designing and dividing modules, designing and dividing modules, and adopting solutions to solve problems.
Recently, it has dealt with dynamic library, static library, dynamic static CRT, and MFC. This article summarizes the problems and thoughts encountered during this period.
1. Static library vs. Dynamic library
The static library is essentially the compiled target code (Compiled using VC. CPP file or. the C file will get the target file. OBJ. After compilation, the link program links the target file to the final output file according to the specified requirements. LIB /. dll /. EXE.
Compared with the dynamic library, the static library does not have entry functions and cannot be executed independently or dynamically linked. Once linked to the target file, the code segment/Data Segment of the static library will be merged into the target file. This is the essential difference between a static library and a dynamic library.
Due to the above differences, we can easily understand the following situation: If you define a static or global object in a static library, the object will be linked to the data segment of the target file (the target file may be a DLL or EXE ).
The advantage of the static library is that it is easy to use. You do not need to consider the issue of memory application and release, because the code segment of the static library is part of the target module (exe or DLL ), the new/delete called in the connection phase will be relocated to the CRT function address of the target module.
If you use a DLL, a CRT heap will be initialized in the DLL, therefore, its memory application and release are different from those in the exe crt heap (two different CRT heap). If you apply for a memory from the DLL, finally, it must be handed back to the DLL module for release. Otherwise, heap collision will be generated. In debug mode, you will receive a system located in mallocAnd understand what happened.*
The description here has an error and the correction is as follows:
A dll may not have a self-initialized CRT heap, depending on whether the DLL is dynamically linked to msvcrt or static link to libcmt. Because the CRT maintains a heap through a global variable _ crtheap (in Windows) and initializes the CRT heap during CRT initialization, if the entire application uses the same CRT by linking the dynamic msvcrt, there is no problem. However, if any binary module links to a static CRT, it will have its own CRT heap. Strictly speaking, you should be careful to ensure that the heap memory from a CRT is finally returned to the CRT heap. Otherwise, an error occurs. In debug mode, when you call the free function to release the memory from another CRT heap, there will be a _ asserte (_ crtisvalidheappointer (puserdata); assertion failure, reminding you to use the wrong heap.
If our DLL is linked to a static CRT and released, we should ensure that all the memory from the DLL is recycled by the DLL. The reason is that the DLL has its own CRT heap.
Furthermore, if your static library a depends on the header file of the static library B, and the target application EXE depends on the static library a, When you link the static library, you must also link static library B. Otherwise, some symbols in static library a cannot be found, leading to link failure. If dynamic library a depends on a static library B, you do not need to re-include the static library in the EXE dependent on the dynamic library, because this dynamic library a has linked the static library B to module A, and has a copy in dll a. If the EXE module is not directly dependent on the static library B, in this case, you do not need to link the static library again in the exe.
The above problem is also a problem that may occur when the static library and dynamic library are mixed: If a static library a is used by dynamic library B and exe C, while exe c needs to use dynamic library B, so the code and global data of this file a exist in the dynamic library B and exe C. First, this is a waste of space. Second, this may cause problems. For example, when I add a pointer to an object X in a in EXE C, and pass the pointer to dynamic library B for use. On the surface, it seems that there is no problem, but if this object x references the global/static data in library A, it may cause problems, in this case, dynamic database B has a copy of global/static data in database A, while EXE C has another copy. If this global/static data is used by X, then we will get the inconsistent context environment. What problems may arise depends on how the specific logic is organized. In this case, it is best to re-organize static database a into a dynamic database, so that there is no problem of multiple copies of code and multiple sets of global data. If you cannot do this, you can adopt the DLL export library a interface according to the specific application organization, and exe uses the DLL export interface to access library a without directly linking to library, but this is usually not a fundamental solution.
On the other hand, dll can contain its own resource files, but lib cannot. Because DLL is a complete PE file, and Lib is only packed with several OBJ files. This does not mean that resources (RC) cannot be used when Lib is used. You can use the RC file, resource. H is included in the target application, and can be used normally as long as there is no resource ID conflict, just as you have defined these resources in the resources of the target application. The resources in the DLL belong to the DLL itself and do not conflict with the idnumber of the resources in the EXE, but some handle settings need to be made for the resource during use (refer to afxsetresourcehandle ), in order to allow the API to access resources in the DLL, rather than in the exe. If you want to compile a library module with resources, DLL is indeed the best choice.
2. Static & Dynamic C/C ++ runtime and manifest
The static C-Runtime Library is called libc. Lib. We usually use the multi-threaded version called libcmt. Lib, and the version under debug is called libcmtd. Lib. Dynamic C-runtime, in the VC environment, we use msvcrt. lib and msvcrtd in debug. lib (these two lib are actually two export symbol files, and the actual Runtime Library is located in msvcrt. dll/msvcrtd. DLL (vc6), if the version is vc2005, It is msvcr80.dll/msvcr80d. DLL)
The Runtime Library of C ++. The static version is libcpmt. lib/libcpmtd. Lib. The dynamic versions are msvcprt. lib and msvcprtd. Lib. (Similarly, the actual Runtime Library is located in <vc2005> msvcp80.dll/msvcp80d. dll)
As mentioned in the comparison at the first point, if the DLL module depends on a static library and the EXE dependent on the DLL module also depends on the static library, then there will be two copies of the static library code and global data in the final memory. This is also true for the C/C ++ Runtime Library. It should be noted that, as long as the program is based on C language and C ++ language, almost all will use the C/C ++ Runtime Library. Therefore, when planning a project, if multiple DLL modules are found, it is best to use the dynamic version of The Runtime Library to avoid unnecessary running library code in the final memory.
Another point is about the manifest mechanism added by Microsoft in the XP system and in the compiling environment after vc2005. This mechanism is proposed to solve the DLL Loading Problem with the same name but wrong version. For example, we have two VC compilers, which are different versions. The msvcr80.dll is also different versions, but both are called msvcr80.dll. If we install the application, simply and rudely replace the system directory with the msvcr80.dll that our applications depend on. This may cause problems that previous applications cannot run correctly, because they may depend on other versions of msvcr80.dll.
To solve this problem, encode the running environment, version, and verification value of a DLL to a directory name, place the DLL of this version to the directory of the corresponding name. In this way, even if the DLL name is the same, we can find the DLL of the correct version. But how does the application know which version of DLL is needed? If the application does not know, the operating system does not know which DLL to load even if the system has a correct version of DLL.
Therefore, the manifest file indicates all the modules that the module depends on, and ensures that the specified module is not ambiguous by name, verification code, version, and other information (use NotePad to open a manifest file, you can see the above information). When the application EXE or DLL is loaded by the operating system, the system will find the corresponding module based on the information, first in C: find the/Windows/winsxs directory (open this directory and you will see a large number of running libraries for different versions of CRT/CPRT/mfc/ATL ), if not found, the application will be located in the current directory.
This is why the use of vc2005 to compile a DLL or an EXE always generates a manifest file. Therefore, if you use a dynamic version of the CRT Runtime library or any other DLL, it is best not to disable the compilation option generated by manifest.
3. Dynamic library interface design
If the dynamic library may update versions frequently and provide new functional interfaces, it is worth thinking that the upgrade of the dynamic library does not need to be changed because of its executable modules.
To achieve the above objectives, you must ensure the following:
A. The memory layout of classes in the dynamic library is not exposed to the outside world. That is to say, the. h provided to the user by the dynamic library should not contain the member information of the class. This is because, if the internal data of the class is modified and a variable is added or reduced, the memory occupied by the class is modified, if an EXE uses the class definition of the previous version and a new class object, this part of the Code must be re-compiled once the class definition is modified. The standard practice is that DLL only provides interface definitions to the outside world, but does not provide implementation definitions. That is, it provides a class, but the class only contains pure virtual functions, without Data <this approach is a bit similar to the idea of COM>; or it only provides a series of common functions and a pointer to the implementation class. This approach has a benefit. if you add a new function interface, you do not need to update the external program again, but you do not need to use the virtual function interface.
B. classes in the dynamic library should not provide the ability to construct the structure for the outside world. It is also based on the above reasons. If the new/delete class can be used, then, when the class definition is modified, the application that has to be re-compiled and used in the library may occur. This problem does not exist if you only use the excuse defined in DLL for interaction. For example, you cannot directly create an object, but you must obtain a pointer to an object from a DLL export function. You cannot delete this object externally, instead, it must be sent to another export function and handed to the DLL for deletion. In this way, as long as the DLL remains unchanged, the application dependent on the DLL does not need to be updated when the DLL is updated. (A good practice is to set the constructor of the interface classes provided by DLL to private)
C. dll should use dynamic CRT as much as possible. If MFC is used, dynamic MFC should be used as much as possible. This is to avoid repeated code between DLL and external modules. In addition, if there are other static libraries that DLL needs to depend on, use the dynamic version of the Library as much as possible.
P.s. If you want to learn more about the static library, dynamic library, and C Runtime Library, you can refer to the book "Programmer self-cultivation-link loading and library.
P.s. 2. As the boss of pongba said, it is a good learning process to write down the knowledge that I think there is no problem. During the process of writing this article, I will understand what I think, however, the problems that I really understand are much clearer. The process of writing helps to display the assumptions about the existence of the Middle and Lower Consciousness in the original brain, and re-process the ideas to clarify the original concepts.