简而言之:是的,您可以通过指针访问静态方法。
要理解这一点,最好多了解一下编译器的底层原理。
为清楚起见,编译的程序是用机器代码编写的。“程序加载器”的编译程序中有额外的信息,但程序本身只是处理器执行的指令。
当您在 C 中调用函数“foo()”时,C 编译器会将其转换为“CALL”处理器操作。CALL 操作在代码中后跟 foo 的地址(字面意思是内存地址或“偏移量”)。请注意,因为它是一个内存地址,所以没有使用名称(“foo”)。另请注意,链接器不需要知道“foo”就可以工作。
当您在 C 中调用函数“bar()”并且该函数位于另一个编译单元(另一个 C 文件)中时,编译器会出现一些问题,因为它不知道函数在程序中的位置(内存中的位置)是打电话。那就是它不知道在 CALL 操作之后要写什么地址。发生这种情况时,它会编写代码,为地址留出空间,但为链接器留下注释。注释告诉链接器“把 bar 的地址放在这里”。所以链接器使用内存地址更正编写的程序。允许链接器执行此操作;编译器在代码中编写一个包含每个函数名称和相应地址的表。
那么静态有什么作用呢?这只是告诉编译器不要在传递给链接器的表中写入函数的名称和地址。该函数仍然作为函数存在于代码中,但链接器不知道它在哪里。同一编译单元中的任何代码都将知道函数在哪里。因此,同一编译单元内的任何函数都可以将函数的地址作为编译单元外的指针传递。
用于传递函数指针的 c 代码如下所示:
文件1.h
typedef void (* VoidFunctionPointer)();
extern VoidFunctionPointer somethingInteresting;
bar();
文件1.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;
}
文件2.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();
}
在这段代码中,file2 实际上运行了来自 file1 的静态函数。关键是 file2 永远不需要该函数的名称,因此 static 对函数指针没有影响。
我可以推荐阅读微软对 PE 格式(.EXE 和 .DLL)的描述 [这里]:
http://msdn.microsoft.com/en-us/library/ms809762.aspx