Thread: Where to put our structures?

  1. #1
    Registered User
    Join Date
    Jun 2010
    Posts
    53

    Where to put our structures?

    Hello,

    I am a C programmer. I program micro-controllers... mainly PICs.

    I have a C question about where structure definitions should reside. Most of us create a pair of files called xxx.h and xxx.c and usually put the structure's definition in the header file along with function prototypes. We then put our function implementations in the xxx.c file.

    Lately I took a look at the WinUser.h file and to my surprise I have seen many strutures defined in this file. So why do they define structures in one big common header called WinUser.h when we were taught to define every structure in its own header file in respect to its associated .c file?

    For example, in my project I have a header file called "UDT.h" and this header file contains two (2) structures. I also have a .c file called "UDT.c" which holds all the function implementations that manipulate the structure's data. Here is the header file:

    Code:
    =========================================UDT.h
    typedef struct 	T_udt 	udt;
    
    typedef struct tag_fields  
    {
    unsigned short LKdct__F1; 
    unsigned short LKdct__F2;                    				  
    unsigned short  LKdct__F3;  
    unsigned short  quit_flag;                    			
    unsigned short  title_msg1;  					
    }Tfields; 
    
    struct T_udt  
    { 								 
    unsigned short f__pc_xchoice; 				        
    unsigned short f__list_lenght; 				
    unsigned short IndexesUsed;
    Tfields	*fields;                     
    }; 
    =====================================

    Now there is three (3) ways we can do this, where we can:

    A) Define the two (2) structures in the same header file as done above

    OR

    B) Define only the "tag_fields" structure in a "Com.h" header (like the WinUser.h does) and keep the "T_udt" structure in the "UDT.h" file

    OR

    C) Define both structures in a "Com.h" header (like the WinUser.h does)

    Which would be to most politically correct way to do this. Confused.

    All feedback or help is appreciated.

    rob

  2. #2
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    I think you're making a conceptual error here... WinUser is a huge library but it only contains a very small portion of the overall Windows API. If you look at other headers in the Windows API you will discover structures, variables, functions, etc. prototyped in almost all of them. The API follows the common convention of defining what's needed and what's in a specific library, although because of it's size, some libraries will have more than one associated header.

    The general rule of paired files is still the best practice...

  3. #3
    Registered User
    Join Date
    Jun 2010
    Posts
    53
    Hello CommonTater,

    Yes but what if some other .c file (for example "other.c") needs the "tag_fields" structure.... Then wouldn't it be a good idea to put it in a common header "Com.h" file and have the other.c file include the "con.h" file so it can use the "tag_fields" structure !!!!!

    I mean perhaps the "T_udt " structure is well in its place that is in the "UDT.h" file where it belongs since it has a close relation with the "UDT.c" implementation file. But the "tag_fields" structure should be available for re-usability for the overall project... no?

    I mean mind you, this is a little shady for me...... please do get back.

    Thankyou for your reply... it is very appreciated.
    r

  4. #4
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by see the big C View Post
    Which would be to most politically correct way to do this. Confused.
    I suppose that one struct -- one .c -- one .h is a not a bad rule of thumb in the absence of any other organizing principle, but in my experience I don't find what you describe exceptional because there is often enough (even: usually) some other organizing principle at work, eg, the one described by CommonTater. Nb. I don't program micro-controllers.

    To be honest, when I do end up with one struct one .c one .h it is only by happenstance, since (to be honest) for me there is always some other organizing principle at work. I have no qualms about using extra headers and consider that normative too. For example, I might have a "constants.h" (with no corresponding "constants.c") included by several .c files that do have corresponding .h's.

    If someone told me this was a politically incorrect methodology I'd just consider them someone with some form of obsessive-compulsive disorder (to be honest).
    Last edited by MK27; 09-01-2011 at 09:41 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  5. #5
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by see the big C View Post
    Hello CommonTater,

    Yes but what if some other .c file (for example "other.c") needs the "tag_fields" structure.... Then wouldn't it be a good idea to put it in a common header "Com.h" file and have the other.c file include the "con.h" file so it can use the "tag_fields" structure !!!!!
    Yes, you can do that... but it blows up the relationship between headers and source, making your source code much harder to maintain.

    If you use "include guards" ...
    Code:
    #ifndef HEADERNAME_H
    #define HEADERNAME_H
    
    // definitions and prototypes here
    
    #endif // HEADERNAME_H
    ...you can simply include the file with the needed struct anywhere it's needed. The include guard prevents the compiler from reading it more than once per source file, so no redefinition erorrs.

    Source code organization is very much dependent upon what you are doing. However disorganized code, with stuff scattered all over the place very rapidly becomes difficult or impossible to maintain... The rules you use should be those agreed upon by your team (or common sense if working alone). Just so you do have some kind of organizational guideline at work...

    For example... I try to keep the .h to .c correlation whenever possible... but this project I'm working on now has a header with a large number of constants defined. Other projects have .c files with no header because the page doesn't export anything... It really is a "by project" decision...
    Last edited by CommonTater; 09-01-2011 at 09:55 AM.

  6. #6
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by see the big C View Post
    Yes but what if some other .c file (for example "other.c") needs the "tag_fields" structure.... Then wouldn't it be a good idea to put it in a common header "Com.h" file and have the other.c file include the "con.h" file so it can use the "tag_fields" structure !!!!!

    I mean perhaps the "T_udt " structure is well in its place that is in the "UDT.h" file where it belongs since it has a close relation with the "UDT.c" implementation file. But the "tag_fields" structure should be available for re-usability for the overall project... no?
    Sorry, I missed this post when I wrote my last reply. I think you could probably accomplish what you want a number of "equally correct" ways. Here's what I would do:

    - if other.c has a header, and one of the prototypes includes a "tag_fields" as an argument, I would #include com.h in other.h, exactly the way I would a standard library header if required.

    - if the struct is not used in a prototype, ie, not required to parse other.h, I would just #include com.h in other.c. This can mitigate re-definition issues, altho if you use include guards as CommonTater recommends that will not be an issue anyway. It also reduces clutter in your .h files.

    If all the functions associated with "tag_fields" are defined in the various .c files that include it, then there is no need for a com.c, right? Nothing wrong with that either, if it's what makes sense.
    Last edited by MK27; 09-01-2011 at 10:00 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  7. #7
    Registered User
    Join Date
    Jun 2010
    Posts
    53
    Hi guys,

    MK27:

    <
    -if other.c has a header, and one of the prototypes includes a "tag_fields" as an argument, I would #include com.h in other.h, exactly the way I would a standard library header if required.
    >

    And this is exactly my case. Below is a couple of modules which use the Tag_Fields structure in different ways. What is wrong with storing the "Tag_Fields" structure in a common file (COM.h) along with many other stryctures of the like and using it as shown below. Here a quick sample.... please excuse me for I have coded this up really quickly and did not try to compile it so therefore there might by syntax errors. However, the sample below is simply there to get the idea of what we are discussing. Thanks for your comprehension!


    Code:
    =========================================COM.h
    typedef struct tag_fields  
    {
    unsigned short LKdct__F1; 
    unsigned short LKdct__F2;                    				  
    unsigned short LKdct__F3;  
    unsigned short quit_flag;                    			
    unsigned short title_msg1;  					
    }Tfields; 
    
    
    =========================================UDT.h
    #include "COM.h"
    
    typedef struct  T_udt udt;
    
    struct T_udt  
    { 								 
    unsigned short f__pc_xchoice; 				        
    unsigned short f__list_lenght; 				
    unsigned short IndexesUsed;
    Tfields	*fields;                     
    }; 
    
    udt* newUDT();
    =========================================UDT.c
    #include "UDT.h"
    
    udt* newUDT(){
    udt* pUdtObj;
    
    pUdtObj = (udt*)malloc(sizeof(struct T_udt));
    // set udt member defaults here
    
    pDefObj->fields = (Tfields*) malloc(sizeof(struct tag_fields));
    // set tag_fields members here
    
    return pUdtObj;
    }
    
    =============================================
    
    
    
    =========================================ABC.h
    #include "COM.h"
    
    typedef struct  T_abc abc;
    
    struct T_abc  
    { 								 
    unsigned short xxx; 				        
    unsigned short yyy; 				
    unsigned short IndexesUsed;
    Tfields	*fields;                     
    }; 
    
    abc* newABC();
    
    =========================================ABC.c
    #include "ABC.h"
    
    abc* newABC(){
    abc* pAbcObj;
    
    pAbcObj = (abc*)malloc(sizeof(struct T_abc));
    // set udt member defaults here
    
    pAbcObj->fields = (Tfields*) malloc(sizeof(struct tag_fields));
    // set tag_fields members here
    
    return pAbcObj;
    }
    =============================================
    
    
    =========================================DEF.h
    #include "COM.h"
    
    typedef struct  T_def def;
    
    struct T_def  
    { 								 
    unsigned short www; 				        
    unsigned short vvv; 				
    Tfields	*fields;                     
    }; 
    
    def* newDEF(*Tfields pTFieldsObj);
    =========================================DEF.c
    #include "DEF.h"
    // functions implementatios
    
    def* newDEF(*Tfields pTFieldsObj){
    def* pDefObj;
    
    pDefObj = (def*) malloc(sizeof(struct T_def));
    // do other default settings...
    
    pDefObj->fields = pTFieldsObj;
    
    return pDefObj;
    }
    
    // other function implementations ....
    =============================================
    
    int main()
    {
    udt* pUdtObj;
    abc* pAbcObj;
    def* pDefObj;
    TFields  fields;
    
    pUdtObj = newUDT();      // An udt object setting the members of the Tfields object *in* the new() function! 
    pAbcObj = newABC();      // Another object "abc"  setting the members to the Tfields object *in* the new() function! 
    
    //.... other code here 
    
    fields.LKdct__F1 = 10;    
    fields.LKdct__F2 = 11;
    fields.LKdct__F3 = 12;
    fields.quit_flag = 1;                    			
    fields.title_msg1 = 100;  
    
    pDefObj = newDEF(&fields);   // Another object "def" preseting the TFields members and then passing in the address of the TFields object! 
    
    // ... other code
    
    // All free operations here.....
    
    return 0;
    }
    
    ================================================
    Regards
    r

  8. #8
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by see the big C View Post
    What is wrong with storing the "Tag_Fields" structure in a common file (COM.h) along with many other stryctures of the like and using it as shown below.
    Nothing, altho if def.h and abc.h are both included in the .c file with main(), you'll have to put include guards in com.h (as per CommonTater post #5 above).
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  9. #9
    Registered User
    Join Date
    Jun 2010
    Posts
    53
    <
    Nothing, altho if def.h and abc.h are both included in the .c file with main(), you'll have to put include guards in com.h (as per CommonTater post #5 above).
    >

    Yes. Absolutely. I usually include inclusion guards in all my .h files anyways for best security. Although I am not sure about this, I probably wouldn't need to if all my header files only include "COM.h"! I don't know I would have to carefully think about this.

    Thanks guys!

  10. #10
    Registered User
    Join Date
    May 2009
    Posts
    4,183
    Do not use the name com.h; most programmers with hardware experience will assume com means communications.
    I have seen projects that use common.h to include all of the project headers in one file; I consider it a valid way to program.
    NOTE: I would still put header guards in all the .h files.

    I also use const.h, global.h or globals.h, and type.h or types.h if there is things that do not fit in a header file that matches a c/cpp file.

    Note: I do not normally use an globals.c file with my globals.h; but others on this and other sites consider that bad practice.
    NOTE: Most of the people consider just have global variables bad practice; but, I have found in the embedded world it is needed because of lack of stack space.

    Tim S.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Structures as members of structures & offset
    By trish in forum C Programming
    Replies: 24
    Last Post: 07-16-2011, 05:46 PM
  2. Problems with Nested Structures and Arrays of Structures
    By Ignoramus in forum C Programming
    Replies: 4
    Last Post: 03-02-2010, 01:24 AM
  3. Structures, passing array of structures to function
    By saahmed in forum C Programming
    Replies: 10
    Last Post: 04-05-2006, 11:06 PM
  4. Accessing structures contained in structures
    By enigmaatj in forum C Programming
    Replies: 1
    Last Post: 04-18-2002, 08:53 AM
  5. Replies: 5
    Last Post: 04-11-2002, 11:29 AM