2010-02-02 37 views

Trả lời

19

Điều đó phụ thuộc vào ý bạn bằng cách "truy cập". Tất nhiên, chức năng không thể được gọi bằng tên trong bất kỳ tập tin nào khác vì nó là static trong một tệp khác, nhưng bạn có một con trỏ hàm cho nó.

$ 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

Không, trừ khi có lỗi trong trình biên dịch. Thông thường, mã chức năng tĩnh không được gắn thẻ với tên được sử dụng để xuất hàm trong tệp đối tượng, vì vậy nó không được hiển thị cho trình liên kết và nó không thể liên kết đến nó.

Điều này tất nhiên chỉ áp dụng khi gọi hàm theo tên. Mã khác trong cùng một tệp có thể lấy địa chỉ hàm và chuyển nó vào một hàm không tĩnh trong tệp khác và sau đó hàm từ tệp khác có thể gọi hàm tĩnh của bạn.

4

Theo tiêu chuẩn, không thể truy cập chức năng tĩnh bên ngoài phạm vi của tệp theo tên do liên kết nội bộ. Tên của nó không được xuất và không được cung cấp cho trình liên kết. Tuy nhiên, nó vẫn có thể được truy cập và gọi bằng con trỏ hàm, giống như bất kỳ hàm nào khác.

16

Nó có thể được gọi từ bên ngoài phạm vi thông qua con trỏ hàm.

Ví dụ, nếu bạn có:

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

typedef int (*FUNC_PTR)(int); 

FUNC_PTR get_pointer(void) 
{ 
    return transform; 
} 

sau đó một chức năng nằm ngoài phạm vi có thể gọi get_pointer() và sử dụng con trỏ hàm trở lại gọi biến đổi.

+1

Tôi nghĩ rằng nên là "int (* get_pointer (int)) (void)". – paxdiablo

+0

@paxdiablo và @caf - cảm ơn bạn. –

1

Không, mục đích của từ khóa tĩnh là giới hạn phạm vi của tên hàm thành tệp.

6

Không thể truy cập bên ngoài tệp theo tên của nó. Tuy nhiên, bạn cũng có thể gán cho nó chức năng con trỏ và sử dụng nó bất cứ nơi nào bạn muốn.

3

Chỉ với mẹo vặt. Chức năng thường không hiển thị với trình liên kết để nó không cho phép bạn thực hiện nó.

Nhưng, nếu bạn cung cấp một chức năng bên trong đơn vị biên soạn cùng (như chức năng tĩnh) mà trả về địa chỉ của hàm:

Trong main.c:

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

Trong hidden.c:

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

Điều này sẽ dẫn đến chức năng tĩnh get7 đang được gọi.

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

"Đã truy cập"? Nó phụ thuộc vào ý của bạn bằng thuật ngữ này. Tôi giả sử khi bạn nói "hàm tĩnh", bạn đang nói về hàm độc lập được khai báo static (tức là được khai báo với liên kết bên trong) trái ngược với hàm thành viên lớp tĩnh trong C++, vì hàm sau là obviosly và dễ truy cập từ mọi nơi.

Hiện tại, một hàm độc lập được khai báo static có liên kết nội bộ. Không thể là được liên kết với từ bất kỳ đơn vị dịch nào khác.Hoặc, đặt nó khác đi, nó không thể được gọi là theo tên từ bất kỳ đơn vị dịch nào khác. Nếu đó là những gì bạn có nghĩa là "truy cập từ bên ngoài phạm vi tập tin", sau đó không, nó không thể được thực hiện. Tuy nhiên, nếu các đơn vị dịch khác bằng cách nào đó có một con trỏ đến hàm đó (nghĩa là nếu bạn bằng cách nào đó cho phép con trỏ đó "rò rỉ" vào thế giới bên ngoài), thì ai cũng có thể gọi hàm đó bằng cách thực hiện cuộc gọi không trực tiếp và do đó "Truy cập nó. Ví dụ, nếu bạn khai báo

static void foo_static(void) { 
} 

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

sau đó trong bất kỳ đơn vị dịch thuật khác, người dùng sẽ có thể làm

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

và cuộc gọi sẽ được chuyển tới chức năng foo_static của bạn. Tôi không biết liệu loại quyền truy cập đó có đủ điều kiện để "truy cập" trong câu hỏi của bạn hay không.

Các vấn đề liên quan