C编码设计-函数指针?


24

我有一个PIC18F46K22,并使用XC8编译器对其进行了编程。最后,我将拥有一个像PC这样的系统,stdin并带有和stdout。因此,在主循环中将有一个函数来检查是否有新输入。如果有输入,将相应地调用一个函数。因此,例如,当我在A上输入A时stdin,PIC将运行类似的函数,function_A而不是function_B在我输入B时调用的函数。

当PIC完成该功能后,我希望将新输入发送到该功能。因此,当按A打开RS232发送器时,从此刻开始,所有输入都将通过RS232发送。最后,该项目是一个独立的文本编辑器。因此,当按A键打开文件系统时,此刻不再是文本编辑,而是浏览文件列表。这意味着按下“向上”和“向下”意味着与在文本编辑环境中有所不同。

我已经做了很多关于如何使用C进行编程的思考。昨晚我想了一下,想知道是否有可能,如果有可能,如何做。我想做的是:

  • main函数调用类似function_A
  • function_A将全局变量更改function_addr为函数的地址指针in_function_A
  • 从那时起,mainfunction_addr有新输入时调用该函数。

所以我需要一个main检查是否function_addr为零的函数。如果是这样,应调用“正常”函数,如function_A。如果不是,function_addr则应调用at中的函数。我还需要function_A将更function_addr改为的指针in_function_A

注意:当应关闭文件系统功能时,is_function_A应将其更改function_addr为0。

所以基本上我的问题是我怎么能

  • 获取函数的地址(并将其存储在变量中)
  • 在指定地址调用函数

6
题外话。属于stackoverflow.com。
user207421

对我来说,状态机方法比处理函数指针的风险要低得多。您的输入字节将传递到状态机结构(可能像开关盒一样简单),该结构根据状态变量或变量而跳至代码的各个位。另外,您不清楚您的stdin来自何处(不是真的很重要,但我很好奇)。
亚当·劳伦斯

9
@EJP我不同意。仅仅因为存在重叠并不意味着它必须在一个站点或另一个站点上。它正在问与低级嵌入式系统的设计和编程有关的问题,这在任何地方都可能是话题。
Kortuk 2013年

状态机可以基于函数间接调用:对状态转换函数的调用返回一个新的状态转换函数。
卡兹(Kaz)

1
让我们有这样的讨论在这里

Answers:


21

功能

int f(int x){ .. }

获取函数的地址(并将其存储在变量中)

int (*fp)(int) = f;

在指定地址调用函数

int x = (*fp)( 12 );

3
+1,在C和ASM世界中很明显,但是对于那些开始使用OO语言的人来说却不是那么明显。
Anindo Ghosh

4
fp调用也可以写成'int x = fp(12);' 以提高可读性。
Rev1.0 2013年

1
我不得不承认,目前主要在C#和Java中工作,我有时会想念C中那些很好的旧函数指针。如果做得不正确,它们会很危险,大多数任务可以通过其他方式完成,但是在确实派上用场的那几次中,它们肯定有用
CVn

@MichaelKjörling:的确如此。我经常在嵌入式C和C#编程之间切换(甚至为设备和PC之间的通信实现类似的代码),尽管像C#一样强大,但我仍然非常喜欢C。
Rev1.0 2013年

2
fp(12)不会增加的可读性(*fp)(12)。它们具有不同的可读性。(*fp)(12)提醒读者它fp是一个指针,也类似于的声明fp。在我看来,此样式与X11内部和K&R C等旧资源相关联。它可能与K&R C相关联的一个可能原因是,在ANSI C中,可以fp使用函数语法来声明,如果fp有一个参数: int func(int fp(double)) {}。在K&R C中应该是int func(fp) int (*fp)(double); { ... }
卡兹(Kaz)2013年

17

尽管Wouters的回答是绝对正确的,但这也许对初学者更友好,并且是有关您的问题的更好示例。

int (*fp)(int) = NULL;

int FunctionA(int x){ 
    return x + x;
}

int FunctionB(int x){ 
    return x * x;
}

void Example(void) {
    int x = 0;

    fp = FunctionA;
    x = fp(3);  /* after this, x == 6 */

    fp = FunctionB;
    x = fp(3);  /* after this, x == 9 */
}

如果不清楚函数指针实际上已分配了目标函数地址,则明智的做法是执行NULL检查。

if (fp != NULL)
    fp(); /* with parameters, if applicable */

8
+1为空检查,但请注意,编译器可能无法保证RAM中fp恰好占用的地址的值最初实际上为NULL。我可以肯定地说int (*fp)(int) = NULL;,是将声明和初始化结合起来使用-由于某些高飞值恰好在那里,所以您不想跳到某个随机存储器位置。然后fp就像在Example()函数中那样分配。
CVn 2013年

1
感谢您的评论,我添加了NULL初始化。
2013年

4
@MichaelKjörling很好,但是如果fp是“全局变量”(如上面的代码所示),则可以保证将其初始化为NULL(不必显式地)。
Alok
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.