我们如何来到这里
声明功能点的C语法旨在反映用法。考虑如下的常规函数声明<math.h>
:
double round(double number);
要获得一个点变量,您可以使用
fp = round;
您需要以fp
这种方式声明该点变量:
double (*fp)(double number);
因此,您所要做的就是查看如何使用该函数,并使用指针引用将该函数的名称替换round
为*fp
。但是,您需要额外的paren集,有人会说这使它更加混乱。
可以说,这在原始C语言中更容易了,它甚至没有函数签名,但是让我们不要回到那里了,好吗?
变得特别讨厌的地方是弄清楚如何声明一个函数,该函数要么作为参数,要么返回指向函数的指针,或两者兼而有之。
如果您具有功能:
void myhandler(int signo);
您可以通过以下方式将其传递给信号函数(3):
signal(SIGHUP, myhandler);
或者如果您想保留旧的处理程序,则
old_handler = signal(SIGHUP, new_handler);
这很容易。使声明正确是一件很容易的事情-也不是很漂亮,也不是很容易。
signal(int signo, ???)
好了,您只需返回函数声明,然后将名称交换为点引用即可:
signal(int sendsig, void (*hisfunc)(int gotsig));
由于您未声明gotsig
,如果省略以下内容,可能会更易于阅读:
signal(int sendsig, void (*hisfunc)(int));
或者可能不是。:(
除了那还不够好,因为signal(3)还返回旧的处理程序,如下所示:
old_handler = signal(SIGHUP, new_handler);
因此,现在您必须弄清楚如何声明所有这些内容。
void (*old_handler)(int gotsig);
对于您要分配给的变量就足够了。请注意,您实际上并没有gotsig
在这里声明old_handler
。这样就足够了:
void (*old_handler)(int);
这使我们对signal(3)有了正确的定义:
void (*signal(int signo, void (*handler)(int)))(int);
救援的Typedef
到这个时候,我想每个人都会同意那是一团糟。有时候,最好为抽象命名。经常,真的。有了权利typedef
,这将变得更容易理解:
typedef void (*sig_t) (int);
现在您自己的处理程序变量变为
sig_t old_handler, new_handler;
并且您对signal(3)的声明变为
sig_t signal(int signo, sig_t handler);
突然之间就可以理解了。消除*也消除了一些令人困惑的括号(他们说括号总是使事情更容易理解-哈!)。您的用法仍然相同:
old_handler = signal(SIGHUP, new_handler);
但现在您有机会了解,的声明old_handler
,new_handler
甚至signal
当您初次遇到它们或需要编写它们时也是如此。
结论
极少数的C ++程序员,事实证明,能够制定这些东西对自己正确的声明没有咨询的参考材料。
我知道,因为我们曾经在面试问题中遇到这个问题,专门针对从事内核和设备驱动程序工作的人员。:)当然,当他们在白板上崩溃并被烧死时,我们就失去了很多候选人。但是我们也避免雇用那些声称自己在该领域有过经验但实际上无法完成工作的人员。
但是,由于存在这种普遍的困难,有一种方法来处理所有不再需要您成为三位字母的怪胎程序员的方法,而不是明智的做法,而且确实合理,因为要使用此方法,其平均值要高出三个西格码。有点舒服。
f :: (Int -> Int -> Int) -> Int -> Int