0

I have three *.h files:

A.h:

<some types>
extern sometype1 somevar1;

B.h:

<some types>
extern sometype2 somevar2;

C.h:

<some types>
extern sometype3 somevar3;

And I have the D.c file:

#include "A.h"
#include "B.h"
#include "C.h"

int freethemall()
{
    TheFunctionFromAhFileForFreeingTheSomevar1Resources();
    TheFunctionFromBhFileForFreeingTheSomevar2Resources();
    TheFunctionFromChFileForFreeingTheSomevar3Resources();
}

This project is some kind of framework.

Sometimes I don't need all the modules - A, B or C, for example, I will need only A and B modules. But the structure of my framework initialization is as follows:

#include "A.h"
#include "B.h"
<Frameworkname>Init();

<do some code here>

<Frameworkname>Free();

So, it's very very uncomfortable to call all the Free functions from every module instead of only one ...Free() function:

#include "A.h"
#include "B.h"
<Frameworkname>Init();

<do some code here>

<Frameworkname><modulename1>Free();
<Frameworkname><modulename2>Free();
..
<Frameworkname><modulenameN>Free();

In this case N is only 2, but I have about 20 modules, so It will be not programmer-friendly to count them all.

How can I change freethemall() function to call only destructor of modules that I used and included? Note, that D.h contains that function and there are a lot of modules that include D.h.

P.S. I can include D.h module in every other module if its needed.

As other way to solve it, I need a function that will be called before the module finalization as in last Delphi languages:

Unit ...

Finalization
   Callme;
End.

There is no need to call it from freethemall(), but it's some kind of lead to solve this problem.

Thank you for any advice.

alk
  • 69,737
  • 10
  • 105
  • 255
Alex Tiger
  • 377
  • 3
  • 22
  • 1
    It is quite weird to design a framework's concept of which modules are being used on which *headers* were included. In my opinion, including a header is passive, it shouldn't change what the program *does*: we have functions for that. – unwind Nov 11 '13 at 16:26
  • if you're only going to be including the header files that will need freeing, why not check if a constant defined only in one of the header files is existent, and if so, then free the module's stuff? – EdgeCaseBerg Nov 11 '13 at 16:31
  • @unwind: Ok, I have the next modules: `smlraster.h/c smlevents.h/c smltime.h/c` Every module has its own functions and is used for some different things. I have the next variables in this modules: `SmlRaster smlraster;` `SmlEvent smlevent;` `SmlTime smltime;` Every variable contains pointers, data, strings and other stuff that is needed for this module. But when program ends I need to release the memory, call necessary system functions and etc. How can I do that? – Alex Tiger Nov 11 '13 at 16:40

5 Answers5

1

2 ways:

  1. the "hack" is to do a #define in each module, or if you don't have access to the code of the modules, do a #define USE_A and and ifdef USE_A to actually include the header. So changing the #define will determine if the header gets included and the function for freeing will check that same define.

  2. The correct way is to have a function that "registers" the items you need to free. An array of pointers. so as you create each one, you add it's pointer or a pointer to a function that frees it to the array, then when you need to free, yo just loop through the array and free each one there.

AwokeKnowing
  • 7,728
  • 9
  • 36
  • 47
  • I'd say go with the pointer to a function approach in the register, that points to a module specific function that clears up it's data. – EdgeCaseBerg Nov 11 '13 at 17:01
0

This is the reason they created c++. The overload mechanism would easily solve your problem here. But since you have to do it in C, the only way I know is to use a bitfield

Free(uint32 bitfield){

int i,masklen =32;

for (i=0;i<masklen;i++)
{
  if (bitfield & 1<<i)
    // call free for module i
    // you can have an array of function pointers so that you easily get the right
    // free function each time 
} 
}

Tis will allow you 32 modules if you need more you need a different type for your bitfield

Pandrei
  • 4,843
  • 3
  • 27
  • 44
0

You could create initialization function, that user is required to call during program startup. That function would be passed which modules user would use. Your library would store that information, and on shutdown call appropriate functions.

Example:

/* Header file */

enum SmlModule {
    SML_RASTER = 1,
    SML_EVENT  = 2,
    SML_TIME   = 4
}

int sml_init(int modules);

Then in program:

int main ()
{
    sml_init(SML_RASTER | SML_TIME);
    (...)
    return 0;
}

This approach is used for example by SDL library, see SDL_Init

0

You could use the Header Guards *1 (which are missing anyway) to solve you problem:

Add the Header Guards by modify your headers like this:

A.h:

#ifndef _A_H
#define _A_H

<some types>
extern sometype1 somevar1;

#endif

B.h:

#ifndef _B_H
#define _B_H

<some types>
extern sometype2 somevar2;

#endif

C.h:

#ifndef _C_H
#define _C_H

<some types>
extern sometype3 somevar3;

#endif

And I have the D.c file:

#include "A.h"   /* \                                            */
#include "B.h"   /*  \                                           */
#include "C.h"   /*   + <--- comment in/out here what is needed. */
...              /*  /                                           */
#include "_n_.h" /* /                                            */


int freethemall()
{
    #ifdef _A_H
    TheFunctionFromAhFileForFreeingTheSomevar1Resources();
    #endif

    #ifdef _B_H
    TheFunctionFromBhFileForFreeingTheSomevar2Resources();
    #endif

    #ifdef _C_H
    TheFunctionFromChFileForFreeingTheSomevar3Resources();
    #endif

    ...

    #ifdef __n__H
    TheFunctionFromChFileForFreeingTheSomevar_n_Resources();
    #endif

    return 0;
}

By commenting in/out the #include lines in D.c the defintions of the Header Guards fro the various *.h fiels are used to steer which lines of code in freethemall() are de/activate.


*1 To learn about Header Guard click here and scroll down the answer.

Community
  • 1
  • 1
alk
  • 69,737
  • 10
  • 105
  • 255
-1

I think what you want is impossible.

In C++, it would be possible because the declaration of objects (whether in header or module) can cause code to be executed, but in C it cannot.

If you do this

main.h:

typedef struct {
    void (*init)(void) ;
    void (*exit)(void) ;
    } MODULE ;

A.h:
extern MODULE A ;

B.h
extern MODULE B ;

main.c:

#include    "main.h"
#include    "A.h"
#include    "B.h"

MODULE modules[] = {
&A,
&B,
0,
} ;

Then during init,exit phases you iterate the modules array, calling the appropriate functions for those phases.

That way you only have to maintain 2 lines. That's the most compact and maintainable way I can think of.

user1338
  • 225
  • 1
  • 6
  • I think you meant "impassible", nothing's "impossible" :) Also, c++ is just sugar for C. It didn't create any new thing that is impossible to do with C. It's all assembler. – AwokeKnowing Nov 11 '13 at 17:06
  • So nothing is impossible then? And C++ is just sugar for C? That's news to me. In any case I DO NOT think it is possible to just include a file and have it cause code to be executed without further reference to what was present in that header in some code accessible from main() – user1338 Nov 11 '13 at 17:22
  • I do get what you're saying, but if he has access to the source, you CAN use #defines in a .h file and those can directly affect code execution – AwokeKnowing Nov 11 '13 at 17:26
  • The #defines can only affect what the compiler turns into code. If he (?) were to #define ModuleAFree() as a null expression unless A.h is included, that serves some purpose. But that is just not a good practice at all. My solution allows you to enable/disable the modules by commenting out a single line. And you can see more clearly what is going to happen. – user1338 Nov 11 '13 at 17:59