Search code examples
cinteger

How to solve circular dependencies in C language


The system software includes two sub-modules mod_a and mod_b, which lead to circular dependencies due to the following reasons

  1. mod_a and mod_b need to use the public definition of sys, so they need to include sys_com.h
  2. sys_com.h provides a memory management interface. You need to know the memory node size (sizeof) of each module, so it contains mod_a.h and mod_b.h.

My personal idea is to create a new com.h, move the definitions of MOD_A_TYPE_1 and MOD_B_TYPE_1 to this file, and sys_com.h, mod_a.h and mod_b.h all include header files. We often encounter similar problems during the project development process. What are your principles for dealing with them?Thanks in advance.

// mod_a.h

#include "sys_com.h"

typedef struct
{
    int len;
} MOD_A_TYPE_1;
// mod_b.h

#include "sys_com.h"

typedef struct
{
    int size;
} MOD_B_TYPE_1;
//sys_com.h

#include "mod_a.h"
#include "mod_b.h"

#define SYS_MOD_A_TYPE_1_SIZE           sizeof(MOD_A_TYPE_1)
#define SYS_MOD_B_TYPE_1_SIZE           sizeof(MOD_B_TYPE_1) 

// pool_type
#define SYS_MEM_POOL_MOD_A_TYPE_1       1
#define SYS_MEM_POOL_MOD_B_TYPE_1       2

// @pool_type: SYS_MEM_POOL_MOD_A_TYPE_1/SYS_MEM_POOL_MOD_B_TYPE_1
void* sys_alloc_pool_mem(int pool_type)

Solution

  • sys_com.h provides a memory management interface. You need to know the memory node size (sizeof) of each module, so it contains mod_a.h and mod_b.h.

    Do you? Why? It seems to me that your API has a flag to choose the struct type but it does not need to use the size directly. The way I would do this is to put the #define for the sizes directly in the C file. In fact, I question the need for the #defines at all. What advantage do they give you over directly using sizeof(type)? I think sys_com.h should look like this:

    // pool_type
    #define SYS_MEM_POOL_MOD_A_TYPE_1       1
    #define SYS_MEM_POOL_MOD_B_TYPE_1       2
    
    // @pool_type: SYS_MEM_POOL_MOD_A_TYPE_1/SYS_MEM_POOL_MOD_B_TYPE_1
    void* sys_alloc_pool_mem(int pool_type)
    

    and sys_com.c should do the following

    #include sys_com.h
    #include "mod_a.h"
    #include "mod_b.h"
    
    // If you really must have the #defines
    #define SYS_MOD_A_TYPE_1_SIZE           sizeof(MOD_A_TYPE_1)
    #define SYS_MOD_B_TYPE_1_SIZE           sizeof(MOD_B_TYPE_1) 
    
    void* sys_alloc_pool_mem(int pool_type)
    {
    // Implementation using the #defines or better sizeof(type)
    }
    
    

    Also consider putting include guards1 on all the headers to prevent circular includes e.g. in mod_a.h

    #if !defined(_MOD_A_H)
    #define _MOD_A_H
    
    typedef struct
    {
        int len;
    } MOD_A_TYPE_1;
    
    #endif
    

    1 Many C compilers have #pragma once to do the same thing but it is not standard.