不,为什么不
回答你的问题:不,你不能,按照你的想法(即函数指针)。函数指针是一个具有另一个变量地址的变量。为了说明这一点,请考虑当您有一个foo
指向 function的函数指针时它是如何工作的bar
。
int bar() {
}
void baz(int (*foo)()) {
int x = foo(); // Calls the function pointed to bar foo
}
int main() {
int (*foo)();
foo = &bar;
baz(foo); // Cal baz() passing it foo, which points to bar()
}
foo
持有的是 的地址bar
。当您传递foo
给某个需要函数指针参数的函数(在本例中baz()
)时,该函数取消引用指针,即查看与 关联的内存地址,获取其中存储的地址,foo
在我们的示例中为在该地址bar
调用一个函数(在我们的例子中, )。bar
对此要非常小心:在上面的例子中baz()
说
- 让我看看与之相关的内存
foo
,它里面还有另一个地址
- 从内存中加载该地址,并在该地址调用一个函数。该函数返回一个
int
并且不带参数。
让我们将其与直接调用的函数进行对比bar()
:
void qux() {
int x = bar(); // Call bar()
}
在这种情况下,没有函数指针。有一个地址,由链接器提供。链接器列出程序中的所有函数,并且它知道,例如bar()
在 address 0xDEADBEEF
。所以qux()
里面只有一个jump 0xDEADBEEF
电话。相比之下,在baz
() 中有类似(伪加法)的东西:
pop bar off the stack into register A
read memory address pointed to by register A into register B
jump to memory location pointed to by register B
例如,putch()
调用 from的方式与calls完全一样,而不像这样做的方式:静态链接到您的程序中,因此其中的地址是硬编码的,很简单,因为不需要函数指针来调用 a范围。printf()
qux()
bar()
baz()
putch
putch()
fprintf()
为什么#define
没有答案
#define
是一个预处理器指令,也就是说,#define
在编译器看到你的代码之前,用它们定义的“符号”被替换为它们的值。这意味着#define
使您的程序的动态修改更少而不是更多。在某些情况下这是可取的,但在您的情况下,它对您没有帮助。为了说明您是否定义了这样的符号:
#define Pi 3.14
然后,无论您在哪里使用Pi
它,就好像您键入了3.14
. 因为Pi
不存在,就编译器而言,您甚至无法获取它的地址来指向它。
最接近动态的putch
就像其他人所说的那样,您可以有某种 case 语句、条件语句或全局指针,但putch
函数本身必须以相同的形式存在。
全局函数指针解决方案:
void (*myPutch)(char);
putch(char ch) {
myPutch(ch);
}
int main() {
myPutch = putch_Type_A();
...
myPutch = putch_Type_B();
}
If/then/else 解决方案已在其他答案中提供
goto 解决方案:这将是一个丑陋的(但很有趣!)hack,并且只能在冯诺依曼型机器上实现,但在这些情况下,你可以putch
看起来像这样:
putch(char ch) {
goto PutchTypeB
PutchTypeA:
// Code goes here
return;
PutchTypeB:
// Code goes here
return;
}
然后,您将goto
使用 goto 将指令覆盖到其他内存地址。您必须弄清楚执行此操作的操作码(可能来自反汇编),而这在哈佛架构机器上是不可能的,所以它在 AVR 处理器上可用,但如果笨拙的话,它会很有趣。