Thread: avoiding globals

  1. #1
    Registered User joed's Avatar
    Join Date
    Mar 2004
    Posts
    59

    avoiding globals

    I have a program that uses a large number of global variables to store various settings. I've eliminated some by making them static withing their functions, if they aren't used anywhere else.

    What is the best way to store lots of settings in a useable way? I would actually like to learn how to eliminate all globals, even if it's somewhat impractical.

  2. #2
    C > C++ duders ggs's Avatar
    Join Date
    Aug 2001
    Posts
    435
    .ini file + getvalue("field")
    .sect signature

  3. #3
    Registered User Frobozz's Avatar
    Join Date
    Dec 2002
    Posts
    546
    Well you could make a struct that stores all the variables and then create and pass it into your functions.

  4. #4
    Quote Originally Posted by joed
    I have a program that uses a large number of global variables to store various settings. I've eliminated some by making them static withing their functions, if they aren't used anywhere else.

    What is the best way to store lots of settings in a useable way? I would actually like to learn how to eliminate all globals, even if it's somewhat impractical.
    It's a design issue.

    Globals have two problems:

    - They have an external linkage that make them accessible in read and write by anyone.

    - They have a permanent duration associated to a uniqueness of instance that makes the code sensible to the 'no-reentrant' problem.

    The 'static inside a function' trick can help to solve the first issue, and is sometimes useful.

    The only way to solve both issues is to use code that is independent from the data definition. The actual data are defined statically or dynamically by the user, and only the addresses of them are passed to the functions (actually a pointer to an anonymous or not structure). This is Object Oriented Coding, rather than the more classical (at least in C) Function Oriented Coding.

    Time to read more about Abstract Data Types (ADT). See how the standard FILE data type and its functions are organized. This is the idea.
    Emmanuel Delahaye

    "C is a sharp tool"

  5. #5
    Registered User
    Join Date
    Apr 2004
    Posts
    210
    Quote Originally Posted by Emmanuel Delaha
    Globals have two problems:

    - They have an external linkage that make them accessible in read and write by anyone.
    At least this one could be eliminated by using static on global level. Of course that would not solve the actual problem though :/

  6. #6
    Registered User joed's Avatar
    Join Date
    Mar 2004
    Posts
    59
    I think I'm going to use the .ini file method, although just in memory for now. Loading variables by name seemed too slow to me at first, but I don't think it will hurt much. Besides, they can be copied locally if used repetitiously.

    The remainder of the globals are just stupid Windows-related junk, and are relatively few in number. So I probably won't bother. Thanks for the help!

  7. #7
    Registered User
    Join Date
    Aug 2003
    Posts
    470
    In C I would keep the settings of the program in a global variable struct. Passing the configuation data into each functions unnecessarily clutters the code; functions that accept option parameters will be unnecessarily tied to your specific program.

    Like in C++, you could use singletons, but I don't think there are too many benefits to attemting to mimic this bahavior in C. An example of using global data, as I said above, is as follows.

    Code:
    typedef struct Options {
          int use_x;
          int use_y;
          int use_z;
    } Options;
    
    Options xyz_options;
    then have access functions for the structure;

    Code:
    int options_use_x() 
    {
           return xyz_options.use_x;
    }
    
    int options_use_y()
    {
           return xyz_options.use_y;
    }
    
    void options_use_x(int use_x)
    {
          xyz_options.use_x = use_x;
    }
    ...
    ..
    If xyz_options will be accessed by multiple threads, you may then guard the accesses to xyz_options.

  8. #8
    Registered User joed's Avatar
    Join Date
    Mar 2004
    Posts
    59
    This was very easy to implement, here's the header:

    Code:
    #ifndef H_VAR
    #define H_VAR
    
    typedef struct {
    	char name[17];		// 16 chars + \0
    	float value;
    	int status;
    } VAR;
    
    void var_init();
    
    int mkvar(char *, float);
    int rmvar(char *);
    
    float getvar(char *);
    int setvar(char *, float);
    
    #endif
    Var names are 16 chars or less. When vars are created, it searches for the first one with 0 status and uses that. I'm going to move the status values to a separate array for speed reasons (searching through structures is slowsville.) I also will add options for different data types, but that's trivial. Thanks again.

  9. #9
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Like in C++, you could use singletons, but I don't think there are too many benefits to attemting to mimic this bahavior in C. An example of using global data, as I said above, is as follows.
    You can have lots of fun with the above, assuming I'm interpreting your post correctly. I did this recently while writing a task scheduler for a project that will probably never get done, which uses the same concept:
    Code:
    static TaskList *TaskHandler( TaskInstance **t, Task_h command )
    {
        static TaskList *tasks[ TaskB_MaxSlices ]; /* The tasks. */
    
        ...
    
        switch( command )
        {
            case TaskH_Enqueue:
            {
                /* These are purposefully hidden functions. */
                static int TaskEnqueue( TaskList *x[], TaskInstance *t );
                TaskEnqueue( tasks, *t );
            }
            break;
    
        ...
    }
    
    /* Comment for board readers: This is in effect the 'interface'. */
    int TaskSchedule( TaskInstance *t )
    {
        TaskHandler( &t, TaskH_Enqueue );
        return 0;
    }
    
    /* Comment for board readers: This would be considered 'implementation'. */
    static int TaskEnqueue( TaskList *tasks[], TaskInstance *t )
    {
        TaskList **slice = NULL;
        ...
    Basicly, the header file for the above only shows how to schedule a task,
    complete a task, and cleanup. The rest isn't listed, because the user doesn't
    need to know about them. They're purposefully not prototyped, except for in
    the handler function, and they're defined after said handler. The actual data
    for the table is static inside the hander, and the only way to do anything with
    that data, is by using the interface provided to you.

    Everything is contained in the handler function. There is no other way to get
    at it. At least that's the idea behind it. The reason for the arguments to the
    handler, and the return value from it, are so I can:
    a) update a pointer if I need to.
    b) return a task if I need to.
    c) use the return value for error state.

    Anyway, that's more than what you're interested in, and is probably off topic
    now, but it's rather fun. I'm actually probably going to end up modifying the
    handler so it can handle additional task sets, but that's neither here nor there.

    Quzah.
    Hope is the first step on the road to disappointment.

  10. #10
    Registered User
    Join Date
    Aug 2003
    Posts
    470
    I don't know Quzah. TaskHandler looks a lot like message based programming, where by one function dispatches a command. You could even have the dispatch function return a function pointer when given the command. Since access is only through one dispatch function, any of the static data need not be duplicated, almost like the singleton pattern.

    But what I was think of was something more of the line of

    Code:
    typedef struct Singleton {
           int data;
    } Singleton;
    
    Singleton* get_singleton_instance();
    
    /** .c file **/
    static Singleton* singleton;      
    
    Singleton* get_singleton_instance() 
    { 
           /* or static Singleton* singleton = 0 */
           if (singleton == NULL) {
                  singleton =  malloc(sizeof Singleton);
                  singleton->data = 5;
           }
    
           return singleton;
    }
    As you can see, this solves some of the initialization problems, provided all accesses of singleton are done through get_singleton_instance, which they will be if singleton is a static variable. Although there is a difference in naming and the there is a possibility of the creation other Singleton variables, the result is almost the same if discipline is used. Of course, it's all sort of self-defeating: C programmers are supposed to be used to these type of initialization problems.
    Last edited by okinrus; 09-05-2004 at 10:09 PM.

  11. #11
    Registered User
    Join Date
    Aug 2003
    Posts
    470
    Actually I'm a bit mistaken. Hiding the definition of Singleton in the implementation .c file should succesfully hide the creation of Singleton if there is a foward reference to Singleton in the .h file and all accesses of Singleton can be done through functions. This is sort of like the use of pointer to implementation in C++(pimpl).

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Extern / Globals
    By Tonto in forum C++ Programming
    Replies: 10
    Last Post: 03-15-2009, 11:37 AM
  2. Static Locals VS Globals (Mem Location)
    By csonx_p in forum Windows Programming
    Replies: 2
    Last Post: 06-25-2008, 02:35 AM
  3. Globals initialization
    By New++ in forum C++ Programming
    Replies: 3
    Last Post: 12-30-2004, 01:11 PM
  4. On globals of different modules.
    By BrownB in forum C Programming
    Replies: 1
    Last Post: 07-16-2004, 11:55 AM
  5. Globals, locals and prototypes
    By face_master in forum C++ Programming
    Replies: 1
    Last Post: 09-01-2001, 07:26 PM