2010-05-24 39 views
6

我需要爲客戶端提供一個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!

回答

7

如果你正在使用gcc,你可以使用構造屬性,

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

從GCC文檔

構造屬性促使 功能被稱爲自動 是 - 前執行進入main()。 類似地,在main()已完成 或已調用exit()後,析構函數屬性 會自動將函數自動調用 。 具有這些屬性的函數是 ,用於初始化將在程序的 執行過程中隱式使用 的數據。

您可以提供一個可選的整數 優先級來控制構造函數和析構函數 運行的順序。具有較小 優先級編號的構造函數在具有較大優先級 編號的 構造函數之前運行;相反的關係 適用於析構函數。因此,如果您有 分配 資源的構造函數和 取消分配相同資源的析構函數,則兩個 函數通常具有相同的 優先級。對於 構造函數和析構函數 的優先級是相同的。如果你想向用戶隱藏一個結構,在頭部聲明結構,但在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訪問。

3

如果您希望客戶端代碼能夠使用「t.a = ...」,那麼您無法隱藏結構定義。你想要的是所謂的不透明類型,看起來像這樣:

 
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

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

使用不完全類型的手柄允許編譯器捕捉類型的錯誤,並在實施功能避免鑄造。 – 2010-05-24 07:41:20

+0

編譯器可能會_still_ catch類型錯誤,因爲您的庫代碼與正確類型的變量一起工作。或者,如果你確實意味着給你的函數賦予了錯誤的類型,那麼這是一個用戶錯誤,他們應該會帶來所有的困難:-)正如我所說,這是唯一的方法,而不是唯一的方法。 – paxdiablo 2010-05-24 07:44:15

+0

爲什麼地球上會使用void *並丟失所有類型的檢查? typedef struct MyHiddenStruct MyHandle; MyHandle * allocHandle(); – 2010-05-24 07:54:26