- 论坛徽章:
- 2
|
写得比较乱…… 我整理一下……
函数签名与layout的关系, 可以是多对多的, 也可以是多对一的。
就举2种签名吧:
- void (*legacy1)(void);
- int (*legacy2)(void const*, void const*);
复制代码 两种在C/C++标准库中都存在。atexit, set_newhandler, qsort, bsearch。
但希望它们的签名是这样:
- void (*expect1)(void* ctx);
- int (*expect2)(void* ctx, void const*, void const*);
复制代码 一种方式是每种签名对应一种layout。
一种方式是尽可能让多种签名共用一种layout。
一对一的优势是可以给实现方面提供更多的信息。
这不单关系到实现的质量(比如上面说的, 是否是stateless),
甚至关系到是否能够实现(比如上面说的, fastcall)。
而多对一的方式, 主要是方便记忆……
不需要记住到底应该用哪一个……
因为这个是没有类型检查的, 只能靠文档来描述。
如果记错, 肯定是要跑飞的。
当然, 如果client可以使用C++, 而且不是VC6, 就可以用函数的签名去推导正确的layout。
所以多对一的这个优势是对C而言的。
因为这个东西…… 不是凭空就想去这么做…… 我是被逼无奈啊……
以前我都用各种方法绕过去了(因为很多这种烂回调都是stdcall的)
但遇见OpenCV后我败了……
- typedef void (*CvTrackbarCallback)(int pos);
复制代码 cdecl的。 它通知“某个” trackbar被修改到pos的位置, 但就是不告诉你是哪个trackbar被修改……
要么:
- container all_trackbar;
- void notify_all(int )
- {
- 所有trackbar注意啊,
- 你们当中某个被修改了,
- 自己检查, 然后更新
- }
复制代码 要么:
- trackbar1;
- void update1(int pos) { trackbar1.update(pos); }
- trackbar2;
- void update2(int pos) { trackbar2.update(pos); }
- trackbar3;
- void update3(int pos) { trackbar3.update(pos); }
- ...
复制代码 无论那种, 我都觉得太难看……
为了应付实际的问题, 所以就弄出了这样一种layout。
而且, 它恰好是多对一的。但不是stateless的(虽然暂时够用)。
如果要将这种方案继续范化, 如果考虑到移植性, 我觉得一对一才是王道……
界面需要给实现留有余地, 否则实现要么完成得很差, 要么根本无法完成功能。
这些legacy代码已经犯过这样的错误(这种烂回调, 还有strtok, 还有fd)。
为了修正它们的错误已经要花费不少功夫, 不能让解决问题的方案自身留下问题然后再用方案去弥补…… |
|