2013-09-06 4 views
7

Funktionen und Variablen, die als statisch deklariert sind, haben interne Verknüpfungen und sie haben Dateiumfang und sind für Funktionen in anderen Dateien nicht sichtbar.C- Verknüpfung von Funktionen, die als statisch deklariert wurden

Angenommen, dass ich eine Funktion wie folgt erklären: -

static int foo(int i); 

in einer Datei mit dem Namen file1.c Kann ich auf diese Funktion aus anderen Datei file2.c durch die Verwendung Zeiger.

Ich gehe durch ein Buch, in dem geschrieben steht, dass es getan werden kann, aber ich weiß nicht, wie das möglich ist.

Und das sind die genauen Linien: -.

Weil es interne Bindung hat, foo kann nicht direkt von außerhalb der Datei aufgerufen werden, in dem sie definiert ist (Deklarieren foo statisch sein nicht Verhindern, dass es in einer anderen Datei aufgerufen wird, ein indirekter Aufruf über einen Funktionszeiger ist weiterhin möglich.

+1

Wenn Sie auf die Funktion von anderen Kompilierungseinheiten zugreifen möchten, warum machen Sie sie dann "statisch"? – Jon

+0

@Jon: Sie können einen Rückruf als statisch deklarieren (niemand kann die Funktion durch seinen Bezeichner aufrufen) und seinen Zeiger an eine Setup-Funktion senden, um auf ein Ereignis zu reagieren. Sie erzwingen, dass es eine Callback-Funktion ist und nicht wie eine reguläre Callback-Funktion. – Gauthier

+0

@Gauthier: In diesem Fall müssen Sie nichts mehr tun, als einfach die Adresse an die Angerufenen übergeben: 'takes_callback (foo)' - ich sehe vorgeschlagen, dass Sie das schon. Das OP bittet (wie ich und andere Leute, die geantwortet haben) um einen global zugänglichen Funktionszeiger, was völlig sinnlos ist. Natürlich, die Menschen nicht die wörtliche Frage zu beantworten für moar rep nicht daran hindert * * ... – Jon

Antwort

4

Vielleicht suchen Sie das?

// file1.h 
extern void (*fptr)(void); 

// file1.c 
static void foo(void) 
{ 
    printf("Hello world!\n"); 
} 

void (*fptr)(void) = &foo; //or void (*fptr)(void) = foo; 

// file2.c 
#include "file1.h" 

fptr(); 

Hier foo ist statisch, aber seine Adresse durch einen nicht static globalen Variable verwiesen wird. Und das ist absolut möglich.

2

Die Funktion kann in einer anderen Datei nicht namentlich aufgerufen werden, da sie in einer anderen Datei statisch ist, aber Sie können sie mit dem Funktionszeiger darauf ausführen.

extern int (*pf)(int);

Sie müssen foo dieser Zeiger zuweisen und dann können Sie darauf zugreifen.

1

H2CO3 gibt Ihnen die richtige Antwort, einen anderen Weg:

/* a.h */ 
typedef int (*fptr)(int); 

fptr call_foo(void); 

/* a.c */ 
#include "a.h" 

static int foo(int i) 
{ 
    return i * 2; 
} 

fptr call_foo(void) 
{ 
    return foo; 
} 

/* main.c */ 
#include <stdio.h> 
#include "a.h" 

int main(void) 
{ 
    fptr fn = call_foo(); 

    printf("%d\n", fn(2)); 
    return 0; 
} 
0

Kurz gesagt: Ja, Sie statische Methoden über Zeiger zugreifen können.

Um dies zu verstehen, ist es wahrscheinlich am besten, ein wenig mehr zu verstehen, was unter der Haube des Compilers vor sich geht.

Aus Gründen der Übersichtlichkeit wird ein kompiliertes Programm in Maschinencode geschrieben. Es gibt zusätzliche Informationen im kompilierten Programm für den "Programmlader", aber das Programm selbst ist nur eine Anweisung, die vom Prozessor ausgeführt werden muss.

Wenn Sie eine Funktion "foo()" in C aufrufen, übersetzt der C-Compiler dies in eine "CALL" -Prozessoroperation. Der CALL-Operation folgt im Code die Adresse foo (wörtlich eine Speicheradresse oder "Offset"). Beachten Sie, dass der Name ("foo") nicht verwendet wird, da es sich um eine Speicheradresse handelt. Beachten Sie auch, dass der Linker nicht über "foo" Bescheid wissen muss, damit dies funktioniert.

Beim Aufruf einer Funktion „bar()“ in C und die Funktion ist in einer anderen Übersetzungseinheit (eine andere C-Datei) der Compiler ein bisschen ein Problem hat, weil es nicht da, wo im Programm nicht kennt (wo in Speicher) ist die Funktion anzurufen. Das heißt, es weiß nicht, welche Adresse nach der CALL-Operation geschrieben werden soll. Wenn dies geschieht, schreibt es den Code, der Platz für die Adresse lässt, hinterlässt jedoch eine Notiz für den Linker. Die Notiz teilt dem Linker mit, "gib hier die Adresse der Leiste an". Der Linker korrigiert also das geschriebene Programm anhand der Speicheradresse. Dies dem Linker zu ermöglichen; Der Compiler schreibt eine Tabelle, die jeden Funktionsnamen und die jeweilige Adresse im Code enthält.

Also was macht statische? Dies teilt dem Compiler einfach mit, den Namen und die Adresse für die Funktion in der Tabelle nicht zu schreiben, die an den Linker übergeben wird. Die Funktion existiert immer noch in Code als eine Funktion, aber der Linker weiß nicht, wo es ist. Jeder Code innerhalb derselben Kompilierungseinheit weiß, wo die Funktion ist. Daher kann jede Funktion innerhalb derselben Kompilierungseinheit die Adresse der Funktion als einen Zeiger außerhalb der Kompilierungseinheit übergeben.

Der Code c zu verwenden, um einen Funktionszeiger zu passieren ist so etwas wie dieses:

file1.h

typedef void (* VoidFunctionPointer)(); 

extern VoidFunctionPointer somethingInteresting; 

bar(); 

file1.c

#include "a.h" 
VoidFunctionPointer somethingInteresting; 

static void foo() { 
    // do something interesting; 
} 


void bar() { 
    // we know what foo is because we're in the same compilation unit 
    somethingInteresting = foo; 
} 

file2.c

#include "a.h" 

int main(int argC, char ** argV) { 
     bar(); 
     // we can call somethingInteresting as if it is a function no matter 
     // wether it's declared static in code or not 
     // this can be foo, just as long as we don't have to use the name "foo" 
     somethingInteresting(); 
} 

In diesem Code file2 Im Endeffekt wird eine statische Funktion von Datei1 ausgeführt. Der Schlüssel ist, dass Datei2 niemals den Namen dieser Funktion benötigt, daher hat statisch keine Auswirkung auf Funktionszeiger.

ich empfehlen kann Microsofts Beschreibung des PE-Format (.EXE und .DLL) [hier] zu lesen:

http://msdn.microsoft.com/en-us/library/ms809762.aspx

+0

Die Tatsache, dass Datei2 nie den Namen braucht, ist wahr, aber die mächtige Sache ist, dass Datei1 ändern könnte, auf welche Funktion 'somethingInteresting' zeigt, ohne dass es irgendjemandem erzählt werden muss. – Gauthier

+0

@Gauthier ja du bist richtig, Funktionszeiger sind nicht da, um einfach die 'statische' Einschränkung zu umgehen. Es ist nur ein Nebeneffekt. –

1

Ein weiterer Weg, das zu tun, was ich denke, verwendbar ist, ist zu machen Ihre statische Funktion ein Rückruf.

//------------------------------ 
// file react.c 
#include "event.h" 

static void react_on_event_A(void) 
{ 
    // do something if event_A occurs. 
} 

void react_init(void) 
{ 
    event_setup(EVENT_A, react_on_event_A); 
} 

Hier werden Sie die Einstellung der react_on_event_A Funktion als Rückruf up, die das Ereignis Fahrer nennen kann, aber sonst jemand aus Blockierung der Funktion durch seine Kennung aufrufen. Sie sagen wirklich zu jemand anderem, um diese Funktion zu vermeiden.

Der Event-Treiber kann wie folgt aussehen:

//------------------------------ 
// file event.h 
typedef enum { 
    EVENT_A, 
} event_t; 

void event_setup(event_t event, void (*callback)(void)); 
void event_check_and_run(void); 


//------------------------------ 
// file event.c 
static void (*event_A_callback)(void); 

void event_setup(event_t event, void (*callback)(void)) 
{ 
    if (event == EVENT_A) { 
     event_A_callback = callback; 
    } 
} 

// Scheduled periodically, or reacting on interrupt. 
void event_check_and_run(void) 
{ 
    if (occured(EVENT_A) && (event_A_callback != NULL)) { 
     event_A_callback(); 
    } 
} 

Der Vorteil dabei ist, dass das Modul react steuert, welche andere Module (event in diesem Fall) haben Zugriff auf seine eigene statische Funktion.

Bei den anderen Alternativen (so dass die Funktion static oder nicht, oder einen Zeiger in der Header-Datei zu veröffentlichen), geben Sie den Zugriff entweder niemand oder zu jedermann.

+0

+1, sehr interessant –

Verwandte Themen