隐藏静态库中的结构定义

时间:2010-05-24 07:10:03

标签: c static struct static-libraries

我需要为客户端提供一个C静态库,并且需要能够使结构定义不可用。最重要的是,我需要能够使用全局变量在库初始化之前执行代码。

这是我的代码:

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

显然这段代码不起作用......但要显示我需要做什么......有谁知道如何使这项工作?我谷歌相当多但无法找到答案,任何帮助将不胜感激。

TIA!

3 个答案:

答案 0 :(得分:7)

如果你正在使用gcc,你可以使用构造函数属性

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

来自gcc文档

  

构造函数属性导致   要自动调用的函数   在执行进入main()之前。   同样,析构函数属性   导致调用该函数   在main()之后自动执行   已完成或退出()已被调用。   具有这些属性的函数是   用于初始化将要的数据   在...期间隐式使用   执行该计划。

     

您可以提供可选的整数   优先控制其中的顺序   构造函数和析构函数   跑了。一个较小的构造函数   优先号在a之前运行   具有更高优先级的构造函数   数;相反的关系   适用于析构函数。所以,如果你有   一个分配一个的构造函数   资源和析构函数   两者都释放相同的资源   功能通常具有相同的功能   优先。优先事项   构造函数和析构函数   与指定的相同   namespace-scope C ++对象

如果要隐藏用户的结构,请在标头中声明结构,但在c文件中定义它,传递指针。举个例子:

// 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无法在foo.c之外访问。

答案 1 :(得分:3)

如果您希望客户端代码能够使用“t.a = ...”,那么您无法隐藏结构定义。你想要的是一个opaque类型,看起来像这样:

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

结构定义仅适用于库。如果您不使库源代码可用,则可以将其完全隐藏在库的用户之外。

答案 2 :(得分:2)

C中没有可移植的方法来确保您的代码在main()之前运行。我要做的只是在你的库中保留一个initialised标志,设置为false,然后在调用init函数之前拒绝做任何事情。

如:

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