2010-05-24 4 views
6

Je dois fournir une bibliothèque C statique au client et avoir besoin de rendre une définition de structure indisponible. En plus de cela, je dois être capable d'exécuter du code avant l'initialisation de la bibliothèque principale en utilisant une variable globale.Masquer la définition de structure dans la bibliothèque statique

Voici mon 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; 
} 

Il est évident que ce code ne fonctionne pas ... mais montrer ce que je dois faire ... Tout le monde sait comment faire ce travail? Je google pas un peu mais je ne trouve pas de réponse, toute aide serait grandement appréciée.

TIA!

Répondre

7

Si vous utilisez gcc, vous pouvez utiliser l'attribut constructeur,

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

De la documentation gcc

L'attribut constructeur provoque la fonction d'être appelé automatiquement BE- exécution avant entre principal(). De même, l'attribut destructeur provoque l'appel automatique de la fonction après que main() a terminé ou exit() a été appelée. Les fonctions avec ces attributs sont utiles pour l'initialisation des données qui seront être utilisées implicitement au cours de l'exécution du programme .

Vous pouvez fournir une priorité entier en option pour contrôler l'ordre dans lequel constructeur et fonctions destructor sont exécutées. Un constructeur avec un numéro de priorité plus petit s'exécute avant un constructeur avec un numéro de priorité plus grand; la relation inverse est valable pour les destructeurs. Ainsi, si vous avez un constructeur qui alloue une ressource et un destructeur qui désaffecte la même ressource, les deux fonctions ont généralement la même priorité . Les priorités pour constructeur et les fonctions destructor sont les mêmes que celles spécifiées pour namespace-champ C++ objets

Si vous voulez cacher un struct des utilisateurs, déclarer la struct dans la tête mais le définir dans le c fichier, en passant autour des pointeurs. A titre d'exemple:

// 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 ne peut donc pas être inaccessibles en dehors foo.c.

3

Si vous souhaitez que le code client puisse utiliser "t.a = ...", vous ne pouvez pas masquer la définition de structure. Ce que vous voulez que l'on appelle un type opaque, qui ressemble à quelque chose comme ceci:

 
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); 
} 

La définition de la structure est disponible à la bibliothèque. Si vous ne rendez pas le code source de la bibliothèque disponible, il est possible de le masquer complètement aux utilisateurs de la bibliothèque.

2

Il n'y a pas de manière portable en C pour garantir que votre code s'exécutera avant .Ce que je voudrais faire est de simplement maintenir un drapeau initialised dans votre bibliothèque, mettre à false, puis refuser de faire quoi que ce soit jusqu'à ce que votre fonction init a été appelée.

Comme dans:

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; 
} 
+0

L'utilisation d'un type incomplet pour la poignée permet au compilateur de détecter les erreurs de type, et évite la coulée dans les fonctions de mise en œuvre. –

+0

Le compilateur peut _still_ attraper les erreurs de type puisque votre code de bibliothèque fonctionne avec la variable correctement typée. Ou, si vous vouliez dire que le mauvais type est donné à vos fonctions, c'est une erreur de l'utilisateur et ils méritent toutes les difficultés qu'il apportera :-) Comme je l'ai dit, c'est une façon de le faire, pas la seule. – paxdiablo

+0

Pourquoi diable utilise use void * et perd tout contrôle de type? typedef struct MyHiddenStruct MyHandle; MyHandle * allocHandle(); –

Questions connexes