• AVR Freaks

Hot!General C file structure query

Author
naeem1234
Super Member
  • Total Posts : 453
  • Reward points : 0
  • Joined: 2015/02/19 06:39:28
  • Location: 0
  • Status: offline
2020/07/07 23:03:51 (permalink)
0

General C file structure query

This is a general question.. not directly related to the Microchip XC8 compiler but more to C and H files structure in multi-file projects. How to expose or hide variables and functions using H files? Where to declare and define variables or structs in C or H files? Should there be only 1 header file that contains all exposed variables and functions and include that in all C files or should there be as many H files as many C files in a project and include only the required H files in a C file? Is it ok to include H files in another H file? 
 
I tried to search any recommended ways in GNU, MISRA, Linuxkernal etc but cannot find any consolidated resource so far. can anyone help in this?
 
Your help is highly appreciated.
 
 
post edited by naeem1234 - 2020/07/07 23:56:56
#1

5 Replies Related Threads

    Hen
    Senior Member
    • Total Posts : 86
    • Reward points : 0
    • Joined: 2018/10/24 04:01:44
    • Location: 0
    • Status: offline
    Re: General C file structure query 2020/07/08 00:42:12 (permalink)
    +1 (1)
    Have no clue whats right or wrong but I prefer one header per *object* and sort of keeping related stuff together.
    Theres no limit on inclusion (if the compiler supports it) however you have to guard them with #pragma once or like.
    For good or bad, I tend to have alot more header files than source files.
     
    #2
    crosland
    Super Member
    • Total Posts : 2017
    • Reward points : 0
    • Joined: 2005/05/10 10:55:05
    • Location: Warks, UK
    • Status: offline
    Re: General C file structure query 2020/07/08 02:22:07 (permalink)
    +3 (3)
    It's a very personal choice and you will get conflicting answers.
     
    Start with, for example, https://stackoverflow.com/questions/47919/organization-of-c-files
    #3
    moser
    Super Member
    • Total Posts : 582
    • Reward points : 0
    • Joined: 2015/06/16 02:53:47
    • Location: Germany
    • Status: online
    Re: General C file structure query 2020/07/08 10:59:20 (permalink)
    +3 (3)
    This is how I do it:
     
    naeem1234How to expose or hide variables and functions using H files?

    Variable definition into .c file.
    Variable declaration into .h file.
    For creating the declaration basically copy the definition, add the extern keyword and remove any initialization. Keep the qualifiers (const, volatile) and any __attribute__.
    Exception 1: static variables shall not get exposed, and for those nothing goes into the .h file.
    Exception 2: variables with auto storage (defined inside a function) should not get exposed, and for those nothing goes into the .h file.
    Note: Instead of exposing variables with extern, consider to keep them private and instead create access functions (e.g. variable_get()/variable_set() ).
     
    Function definition into .c file. 
    Function declaration into .h file.
    For creating the declaration basically copy the definition, remove the function body and add a semicolon.
    Exception 1: static functions shall not get exposed, and for those nothing goes into the .h file.
    Exception 2: For a static inline function, which is used in only one .c file everything goes into that .c file and nothing into the .h file.
    Exception 3: For a static inline function, which is used in several .c files or .h files everything goes into an .h file of your choice and nothing into a .c file.
    Exception 4: functions defined inside another function should not get exposed, and for those nothing goes into the .h file.
     
    typedef, which is used in only one .c file, goes into that .c file and nothing goes into the .h file.
    typedef, which is used in several .c files or .h files, goes into a .h file of your choice and nothing goes into a .c file.
    Exception 1: typedef defined inside another function should not get exposed, and for that nothing goes into the .h file.
     
    naeem1234Where to declare and define variables or structs in C or H files?

    A struct variable is a variable.
    A struct typedef is a typedef
    For both see the previous answer.
     
    naeem1234Should there be only 1 header file that contains all exposed variables and functions and include that in all C files or should there be as many H files as many C files in a project and include only the required H files in a C file?

    Of course this is a style question. However, if your project gets really large, this 1 header file will get really huge and a real mess. Therefore, usually each .c file should have its own .h file. This gives your program some modularization. For each pair of .c and .h file, the .h file describes the interface to a logical module, and the .c file actually implements it.
    However, it is OK to have additional .h files, which don't have a .c file, typically for typedef, #define, and static inline functions. Furthermore, sometimes you might also have a logical module which has two or more interfaces. And one other .c file might use interface A and a second other .c file might use interface B. Therefore, it makes sense to declare each interface in an own .h file, although they get implemented by the same .c file. For example: module.c, module_interface_A.h, module_interface_B.h.
    In each .c and each .h file you usually only include the required .h files. However, if you have a very general .h file, which you use in the majority of .c files, it is also common to include that one in all .c files, and don't care if it is actually required.
     
    naeem1234Is it ok to include H files in another H file?

    Yes. Examples include:
    - In one .h file you are using a type from a typedef in a second .h file. 
    - In one .h file you have a static inline function, which uses a function, or an extern variable from a second .h file.
    - In one .h file you have whatever, which uses a #define from a second .h file.
    However, as soon as you have an .h file which include other .h files you should use include guards, at least in all those included .h files. Those include guards prevent double inclusion. Better, you use them in all .h files by default.
     
    However, avoid include circles. Those are evil and make your head hurt. ;-)
    And if you follow my advice about include circles, you don't need to read the rest of this post:
     
    If you have a circle you should first think again about your code structure and if your logical splitting into files really makes sense.
    If you have a circle because of types, you could create an additional .h file for the types.
    If you really think there is nothing wrong with your modularization and this circle can't be avoided, then this is a case where you should create additional .h files:
    Remove from A.h everything which needs any stuff from B.h and place it into an own A2.h.
    Remove from B.h everything which needs any stuff from A.h and place it into an own B2.h.
    After this hopefully,
    A2.h only needs to include B.h, and not B2.h, or
    B2.h only needs to include A.h, and not A2.h.
    If one of those two conditions is true, you are happy. Otherwise, you are screwed, and probably did not really think about your code structure, and ... What the hell are you actually trying to do?!?!?
    post edited by moser - 2020/07/08 11:06:00
    #4
    kmhillatuha
    New Member
    • Total Posts : 12
    • Reward points : 0
    • Joined: 2020/06/25 17:34:33
    • Location: 0
    • Status: offline
    Re: General C file structure query 2020/07/11 20:55:06 (permalink)
    +1 (1)
    First rule, declare things before their use. A variable declared outside a function is considered to be module-global, that is, it's global within the module or file.

    The keyword static has special meaning with module-global variables that's different than local variables. For module-globals the keyword static restricts their scope to the module in which the module-global is declared, causing the variable to be private to that module. This restriction in helpful in avoiding name conflicts between global variables in different modules.

    The keyword extern used with a global variable declaration tells the compiler that variable is already allocated elsewhere. Hence, extern extends the scope of a module-global from another module, to be more global.
    #5
    Hen
    Senior Member
    • Total Posts : 86
    • Reward points : 0
    • Joined: 2018/10/24 04:01:44
    • Location: 0
    • Status: offline
    Re: General C file structure query 2020/07/12 21:01:06 (permalink)
    +1 (1)
    moser
    However, avoid include circles. Those are evil and make your head hurt. ;-)
     

    Nice post Smile: Smile
     
    Regarding circular dependences I very much agree and that goes for classes as well.
    Sooner nor later you end up having no idea what is going on.
     
    Like you say, it's easy enough to separate out messy things and but it in an object/header *below*.
     
    #6
    Jump to:
    © 2020 APG vNext Commercial Version 4.5