Lack of modular support for C Language

Source: Internet
Author: User

ModularIs one of the highest principles in the book "Unix programming art", the first in Unix philosophy: module principle), we should consider how to use it in a concise and clear way.CLanguage modularization.

In addition to C/C ++, it is hard to imagine the lack of standardized module management mechanisms in other popular development languages. But this is also determined by the design philosophy of C language itself: leave as many possibilities as possible to programmers. You can customize what you need based on your actual system and actual needs.

For giant systems such as Windows, a binary modular solution is generally considered. The module provides metadata or uses a unified management solution such as the registry ). A slightly smaller system is usually developed), we will consider lightweight source code-level solutions.

The first thing to consider is the module dependency and initialization process.

Dependency can be solved by the linker or loader. Especially when using C language, a simple static library or dynamic library won't cause much trouble.

C ++, otherwise, some features of C ++, such as the construction of static members of the template class, must be enhanced for the linker that was only used by C language in the early stage. Even a well-written C ++ library may have some unexpected bugs. These bugs often need a deep understanding of the compilation, linking, and loading processes before they can be detected. Note: I do not want to oppose the use of C ++ for development.

What we need to focus on management is the module initialization process.

For a library that is packaged together, such as glibc or msvcrt, the initialization entry and end code at the time of uninstallation are performed. This is not what I want to talk about, but the dependency between smaller modules that we split internally.

It is a problem who initializes first and then initializes later.

In the C ++ language-level solution, a single module is used. The linker determines the order in which initialization code is generated. This usually leads to bugs due to different dependencies and actual build order. Note: I have seen it in several C ++ books to be verified. If you haven't written C ++ for a long time, there is no actual error example); or you can use the inert Initialization Scheme. This inertia Initialization is not omnipotent, and there are some additional overhead. Special notes in multi-threaded environments)

When I used the C language for initial design, I used a simple enough method. That is, according to the encoding specification, each module must have an initialization function with a standard name. For example, the entry to initialize the foo module is

 
 
  1. int foo_init() 

Note: To use a specific module, you must call the module initialization function.

To avoid repeated module initialization, the initialization function is not called directly, but indirectly. Similar to this:

 
 
  1. mod_using(foo_init); 

Mod_using is responsible for calling the initialization function, ensuring that the call is not repeated, and you can also check the circular dependency.

Here, we also agree on the return value after Initialization is successful or not. In our system, return 0 to indicate correct, 1 to indicate failure) and then define a macro for this use.

 
 
  1. #define USING(m) if (mod_using(m##_init,#m)) { return 1; } 

Note: I personally oppose macro abuse. Avoid it as much as possible. We have carefully considered the use of macros here. I hope I can have a code scanner to determine if I missed the module initialization. Maybe I used a module but forgot to initialize it ). Macros can help the code scanning analyzer to implement it more easily. Moreover, using macros is more like a slight and necessary extension to the language.

In this way, at the end of the implementation code of the module in my system, there is an init function, which simply calls USING to reference other modules. For example:

 
 
  1. # Include "module. h"
  2. /*
  3. I personally prefer to put module. h at the end of the source file and before the initialization entry.
  4. It defines the USING macro and related management functions.
  5. This is done to avoid introducing other modules elsewhere in the code.
  6. */
  7. Int
  8. Foo_init ()
  9. {
  10. USING (memory); // reference the memory management module
  11. USING (log); // reference the log Module
  12. Return 0;
  13. }

The uninstallation of modules is not required in most cases. This is not discussed here today.

Link: http://blog.codingnow.com/2010/01/c_modularization.html

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.