2010-02-02 69 views
13

有沒有可能在文件範圍之外評估靜態函數? ?其他文件中的靜態函數訪問

+7

如果你把函數放在頭文件中。那麼在每個編譯單元中將會有一個靜態版本。 – 2010-02-02 08:50:47

回答

19

這取決於你的意思是「訪問」。當然,該函數不能在任何其他文件中被名稱調用,因爲它在不同的文件中是static,但是您有一個指向它的函數指針。

$ cat f1.c 
/* static */ 
static int number(void) 
{ 
    return 42; 
} 

/* "global" pointer */ 
int (*pf)(void); 

void initialize(void) 
{ 
    pf = number; 
} 
$ cat f2.c 
#include <stdio.h> 

extern int (*pf)(void); 
extern void initialize(void); 

int main(void) 
{ 
    initialize(); 
    printf("%d\n", pf()); 
    return 0; 
} 
$ gcc -ansi -pedantic -W -Wall f1.c f2.c 
$ ./a.out 
42 
12

不,除非編譯器中有錯誤。通常情況下,靜態函數代碼沒有標記爲用於在目標文件中導出函數的名稱,所以它不會顯示給鏈接器,並且它不能鏈接到它。

這當然只適用於按名稱調用函數。同一個文件中的其他代碼可以獲取函數地址並將其傳遞到另一個文件中的非靜態函數中,然後來自另一個文件的函數可以調用您的靜態函數。

4

遵循該標準,由於受到內部鏈接的限制,無法在文件的範圍之外通過名稱訪問靜態功能。它的名字沒有被導出,也沒有提供給鏈接器。但是,它仍然可以通過函數指針訪問和調用,就像任何其他函數一樣。

16

它可以通過函數指針從範圍外調用。

例如,如果您有:

static int transform(int x) 
{ 
    return x * 2; 
} 

typedef int (*FUNC_PTR)(int); 

FUNC_PTR get_pointer(void) 
{ 
    return transform; 
} 

那麼範圍外的函數可以調用get_pointer(),並使用返回的函數指針調用轉換。

+1

我認爲應該是「int(* get_pointer(int))(void)」。 – paxdiablo 2010-02-02 11:26:49

+0

@paxdiablo和@caf - 謝謝。 – 2010-02-02 17:30:48

1

不,關鍵字static的目的是將函數名的範圍限制到文件中。

6

它不能通過名稱在文件外訪問。但是,您也可以將其分配給函數指針並在任何需要的地方使用它。

3

只有詭計。該功能通常對鏈接器不可見,所以它不會讓你這樣做。

但是,如果你提供相同的編譯單元內的函數(靜態函數),它返回函數的地址:

main.c

#inclde <stdio.h> 
int (*getGet7(void))(void); 
int main (void) { 
     int (*fn)(void) = getGet7(); 
     printf ("Result is: %d\n", fn()); 
     return 0; 
} 

hidden.c

static int get7 (void) { 
     return 7; 
} 
int (*getGet7(void)) (void) { 
     return get7; 
} 

這將導致調用靜態函數get7

pax> gcc -o demo main.c hidden.c ; ./demo 
Result is: 7 
5

「Accessed」?這取決於你這個詞的含義。我認爲當你說「靜態函數」時,你說的是獨立函數,聲明爲static(即聲明爲內部鏈接),而不是C++中的靜態類成員函數,因爲後者在任何地方都可以很容易地訪問。

現在,聲明爲static的獨立函數具有內部鏈接。不能將從任何其他翻譯單元鏈接到。或者,換句話說,它不能從任何其他翻譯單位以名稱來提及。如果這就是「從文件範圍之外訪問」的意思,那麼不是,它不能完成。但是,如果其他翻譯單元以某種方式獲得指向該函數的指針(即,如果您以某種方式允許該指針「泄漏」到另一個世界中),那麼任何人都仍然可以通過進行一個直接調用來調用該函數,從而「訪問」它。例如,如果你聲明

static void foo_static(void) { 
} 

extern void (*foo_ptr)(void) = foo_static; 

然後在任何其他翻譯單元,用戶將能夠做到

extern void (*foo_ptr)(void); 
foo_ptr(); 

和呼叫轉到您的foo_static功能。我不知道這種訪問是否符合您的問題中的「訪問」。