Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hide struct definition in static library

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!

like image 380
BobMcLaury Avatar asked May 24 '10 07:05

BobMcLaury


3 Answers

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.

like image 111
Scott Wales Avatar answered Nov 04 '22 13:11

Scott Wales


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.

like image 41
William Pursell Avatar answered Nov 04 '22 13:11

William Pursell


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;
}
like image 40
paxdiablo Avatar answered Nov 04 '22 11:11

paxdiablo