views:

92

answers:

3

Hi, I need to provide a C static library to the client and need to be able to make a struct definition unavailable. On top of that I need to be able to execute code before the main at library initialization using a global variable.

Here's my code:

private.h


#ifndef PRIVATE_H
#define PRIVATE_H

typedef struct TEST test;

#endif


private.c (this should end up in a static library)

#include "private.h"
#include <stdio.h>

struct TEST
{
 TEST()
 {
  printf("Execute before main and have to be unavailable to the user.\n");
 }

 int a; // Can be modified by the user
 int b; // Can be modified by the user
 int c; // Can be modified by the user

} TEST;


main.c

test t;

int main( void )
{
 t.a = 0;
 t.b = 0;
 t.c = 0;

 return 0;
}

Obviously this code doesn't work... but show what I need to do... Anybody knows how to make this work? I google quite a bit but can't find an answer, any help would be greatly appreciated.

TIA!

+3  A: 

If you're using gcc you can use the constructor attribute,

void runs_before_main(void) __attribute__((constructor))
{
    ...
}

From the gcc documentation

The constructor attribute causes the function to be called automatically be- fore execution enters main (). Similarly, the destructor attribute causes the function to be called automatically after main () has completed or exit () has been called. Functions with these attributes are useful for initializing data that will be used implicitly during the execution of the program.

You may provide an optional integer priority to control the order in which constructor and destructor functions are run. A constructor with a smaller priority number runs before a constructor with a larger priority number; the opposite relationship holds for destructors. So, if you have a constructor that allocates a resource and a destructor that deallocates the same resource, both functions typically have the same priority. The priorities for constructor and destructor functions are the same as those specified for namespace-scope C++ objects

If you want to hide a struct from users, declare the struct in a header but define it in the c file, passing around pointers. As an example:

// foo.h
typedef struct private_foo foo;
foo * create_foo(void);
void free_foo(foo * f);

// foo.c
struct private_foo {
    int i;
}
foo * create_foo(void){
    foo * f = malloc(sizeof(*foo));
    if (f) f->i = 1;
    return f;
}
...

foo->i can then not be accessed outside foo.c.

Scott Wales
+2  A: 

If you want the client code to be able to use "t.a = ...", then you cannot hide the struct definition. What you want is called an opaque type, that will look something like this:

public.h:
struct foo;
set_a( struct foo *, int );
struct foo * new_foo(void);

main.c:
#include <public.h>
int main( void )
{ 
    struct foo *k;
    k = new_foo();
    set_a( k, 5 );
}

The structure definition is only available to the library. If you do not make the library source code available, it is possible to completely hide it from the users of the library.

William Pursell
+1  A: 

There is no portable way in C to ensure your code will run before main(). What I would do is just maintain an initialised flag in your library, set to false, and then refuse to do anything until your init function has been called.

As in:

static int initialised = 0;

int init (void) {
    // do something.
    initialised = 1;
    return ERR_OK;
}

int all_other_functions (void) {
    if (!init)
        return ERR_NOT_INITED;

    // do something.
    return ERR_OK;
}
paxdiablo
Using an incomplete type for the handle allows the compiler to catch type errors, and avoids casting in the implementation functions.
Scott Wales
The compiler can _still_ catch type errors since your library code works with the correctly typed variable. Or, if you actually meant the wrong type being given to your functions, that's a user error and they deserve all the hardship it will bring :-) As I said, it's _one_ way to do it, not the only way.
paxdiablo
Why on earth would use use void * and lose all type checking?typedef struct MyHiddenStruct MyHandle;MyHandle *allocHandle();
Mike Weller
As you wish. Since the opaque type is a better way to do it, I'll remove the void* option.
paxdiablo