chanzerre
chanzerre

Reputation: 2429

C- Linkage of functions declared static

Functions and variables declared static have internal linkage and they have file scope and they are not visible to functions in other files.

Suppose that i declare a function like this:-

  static int foo(int i);

in one file named file1.c Can I access this function from other file file2.c through the use pointers.

I am going through a book in which it is written that it can done but I don't know how that is possible.

And these are the exact lines:-

Because it has internal linkage , foo can't be called directly from outside the file in which it's defined.(Declaring foo to be static doesn't completely prevent it from being called in another file; an indirect call via a function pointer is still possible).

Upvotes: 8

Views: 1888

Answers (5)

Philip Couling
Philip Couling

Reputation: 14873

In short: yes you can access static methods through pointers.

To understand this, it's probably best to understand a little more of what goes on under the hood of the compiler.

For clarity a compiled program is written in machine code. There's extra information in the compiled program for the "program loader" but the program itself is just instructions to be carried out by the processor.

When you call a function "foo()" in C, the C compiler will translate this into a "CALL" processor operation. The CALL operation is followed in code by the address of foo (literally a memory address or "offset"). Notice that because it's a memory address, the name ("foo") is not used. Also notice that the linker doesn't need to know about "foo" for this to work.

When you call a function "bar()" in C and the function is in another compilation unit (another C file) the compiler has a bit of a problem because it doesn't know where in the program (where in memory) the function is to call. That is it doesn't know what address to write after the CALL operation. When this happens it writes the code leaving space for the address, but leaves a note for the linker. The note tells the linker "put the address of bar here". So the linker corrects the written program using the memory address. To allow the linker to do this; the compiler writes a table containing every function name and respective address in code.

So what does static do? This simply tells the compiler not to write the name and address for the function in the table passed to the linker. The function still exists in code as a function but the linker doesn't know where it is. Any code within the same compilation unit will know where the function is. So any function within the same compilation unit can pass the address of the function as a pointer outside the compilation unit.

The c code to use to pass a function pointer is something like this:

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 this code file2 in effect runs a static function from file1. The key is that file2 never needs the name of that function thus static has no effect over function pointers.

I can recommend reading Microsoft's description of the PE format (.EXE and .DLL) [here]:

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

Upvotes: 1

Gauthier
Gauthier

Reputation: 41945

Yet another way to do that, which I think is usable, is to make your static function a callback.

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

Here you are setting up the react_on_event_A function as a callback that the event driver can call to, but blocking anyone else from calling the function by its identifier. You are really saying to anyone else to keep off that function.

The event driver may look like this:

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

The advantage of doing so is that the module react controls which other modules (event in this case) have access to its own static function.

With the other alternatives (making the function static or not, or publishing a pointer in the header file), you give access either to no one or to everybody.

Upvotes: 2

David Ranieri
David Ranieri

Reputation: 41017

H2CO3 gives you the right answer, another way:

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

Upvotes: 1

user529758
user529758

Reputation:

Maybe you are looking for this?

// 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();

Here, foo is static, but its address is referenced through a non-static global variable. And that's perfectly possible.

Upvotes: 6

Dayal rai
Dayal rai

Reputation: 6606

The function cannot be called by name in any other file since it's static in a different file, but you can do it using function pointer to it.

extern int (*pf)(int);

You need to assign foo to this pointer and then you can access it.

Upvotes: 2

Related Questions