Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories

Welcome to the new platform of Programmer's Heaven! We apologize for the inconvenience caused, if you visited us from a broken link of the previous version. The main reason to move to a new platform is to provide more effective and collaborative experience to you all. Please feel free to experience the new platform and use its exciting features. Contact us for any issue that you need to get clarified. We are more than happy to help you.

C headers, modular programming and linking

bluecorebluecore Posts: 34Member
Hello,
I have a problem when trying to compile a program with multiple modules. I've made an Abstract Data Type and placed all the declarations and function prototypes into a header "hwconf.h" . The implementation of the ADT is in a different file "hwconf.c" where I included the header. To test this module I've made a simple program "cli.c".
The problem is that when I try to compile the whole program I get a linker error, seeing multiple declarations of the constants defined in "hwconf.h". I tried to figure out what's wrong and I found out that the C compiler , unlike the c++ one, it actualy allocates memory for the constants. How can I avoid the linker error, without usig the "#define" dirrective ? What are the standards for C headers?

Comments

  • Malcolm_McLeanMalcolm_McLean Posts: 241Member
    Globals go like this:

    hwconf.c

    int global_x = 123;

    hwconf.h

    extern int global_x;

    Now you've got one copy of global_x, notionally stored in hwconf.c, but accessible to everyone who includes hwconf.h.
    You must not use the identifier global_x for a different global in the same program, or you will get a collision. For this reason most people would call it something like hwconf_x.





  • bluecorebluecore Posts: 34Member
    I didn't want to use the define directive because I needed a way to declare an array of default strings. I don't know why I never considered using "extern". It works now,
    Thanks !
  • LundinLundin Posts: 3,711Member
    No, no, no! That is [b]not[/b] how you do modular programming in C!

    You don't use global variables at all in modular programming, they are considered very poor programming, and so is the "extern" keyword when used for variables. Also, there is never a reason to use global variables in the C language.


    This is how you write a code module properly in C:

    [code]/* h file for "module" */

    #ifndef MODULE_H /* this is called header guards and they prevent linking errors */
    #define MODULE_H

    void some_function (void);

    void set_x (int x);

    int get_x (void);


    #endif /* MODULE_H */ [/code]

    (The C purist would even write function prototypes as

    extern void some_function (void);

    but that is an advanced topic - the meaning is the same.)

    [code]/* c file for "module" */
    #include "module.h"

    static int _x;

    /* A private variable. The "_" syntax is commonly used for private variables or functions. The static keyword guarantees that the variable can't be accessed from outside of the module, neither accidently nor with purpose. It can however be accessed through the whole code module. */


    void some_function (void)
    {
    }

    void set_x (int x)
    {
    _x = x;
    }

    int get_x (void)
    {
    return _x;
    }[/code]

    [code] /* some c file using "module" */
    #include "module.h"

    int main()
    {
    int y;

    set_x(123);
    ...

    y = get_x() + something;
    }[/code]
  • bluecorebluecore Posts: 34Member
    Isn't that the encapsulation common for Object Orientated Programming? I had problems with the declarations of my global constants, here is my header:
    [code]
    #ifndef HWCONF_H
    #define HWCONF_H

    #include
    #include
    #include

    /*default value for hwAddress*/
    extern const char *DEFAULT_MAC;
    extern const int ADR_LEN;

    /* maximum size for the configuration fields */
    extern const int ADDRESS_SZ ;
    extern const int INTERFACE_SZ ;
    extern const int TYPE_SZ ;
    extern const int CONF_SZ ;

    /*default values for hwInterface and hwType */
    extern const char *DEFAULT_STR ;

    extern const int HW_TYPES_DIM ;

    /*posible values for hwType */
    extern const char *HW_TYPES[4];

    /* hardware configuration */
    typedef struct
    {
    char *hwInterface;
    char *hwType;
    char *hwAddress;
    } HwConf;

    /* Ponter to a hardware configuration */
    typedef HwConf* ConfP;

    /* Initialization */
    int HwConfCreate(ConfP *cp);
    /* Clean-up */
    int HwConfDestroy(ConfP *cp);

    /* check if hwInterface of cp is a valid Interface */
    int HwConfValidInterface(ConfP cp);
    /* check if hwType is a valid type for a hardware address */
    int HwConfValidType(ConfP cp);
    /* check if hwAddress is a valid hardware address */
    int HwConfValidAddress(ConfP cp);
    /* cheack if two configurations are identical */
    int HwConfEqual(ConfP cp1,ConfP cp2);


    #endif

    [/code]

    Now , I figured out that it's better to use "#define" for the non-string values(to save some memory) but for the default values HW_TYPES I needed a way to iterate through them with a for. I don't know another way other than the one with an array of const char *. I don't see a reason to make get functions for global constants. I was planning to make setters and getters for my HwConf object, but for now, it works this way.
  • LundinLundin Posts: 3,711Member
    : Isn't that the encapsulation common for Object Orientated Programming?

    Yes, encapsulation is indeed a fundamental cornerstone in OO.

    I had problems with the declarations of my global
    : constants

    Strictly speaking, you shouldn't need any global constants. The few you need could perhaps be declared as extern, but it isn't pretty and will likely lead to "spaghetti". The important part here is to consider whether the whole program actually needs to know about a particular variable or not. A get function is a better solution, and most modern C compilers know how to inline such functions.


    : Now , I figured out that it's better to use "#define" for the
    : non-string values(to save some memory)

    How exactly does that save memory? #defined constants usually consume -more- memory than const, because when you call a #defined constant from the code, it is usually hardcoded into the machine code, and therefore the program itself gets larger. With const, the compiler is often able to optimize better.

    Also, when you write const you can write the int size explicitly, declare 1 byte ints as chars etc. With defines, everything will be "int".


  • bluecorebluecore Posts: 34Member
    Well, I want these values to make my code more readable and easier to maintain. I thought that by using macros I saved the space requiered by those constants, but since the exe is loaded into memory, you're right.. I saved nothig or spent more.

    For my curiosity , I opened some headers (the ones found in /usr/src and /usr/include on a linux machine) and saw alot of defines for default values, like those from "limits.h".Since I need some of these values at compile-time, I still need to use #define(unlike c++ where I can use only const).

    Thanks for the hints and support!
Sign In or Register to comment.