考虑一个简单,可重用的库.它有一个当前状态的对象,以及一个回调函数来输入它.
typedef struct Context_S Context_T;
typedef size_t (*GetBytes_T) (Context_T * ctx, uint8_t * bytes, size_t max);
struct Context_S {
GetBytes_T byteFunc;
void * extra;
// more elements
};
void Init(Context_T * ctx, GetBytes_T func);
int GetNext(Context_T * ctx); // Calls callback when needs more bytes
Run Code Online (Sandbox Code Playgroud)
用户可能需要一些额外的数据用于回调(如文件指针).库提供了一个额外指针的函数:
void SetExtra(Context_T * ctx, void * ext); // May be called after init
void * GetExtra(Context_T const * ctx); // May be called in callback
Run Code Online (Sandbox Code Playgroud)
但是,如果用户额外数据是常量,则需要他在设置数据之前将常量输出.我可以将函数更改为take/return const,但如果数据不应该是常量,则需要额外的回调.
void SetExtra(Context_T * ctx, void const * ext);
void const * GetExtra(Context_T const * ctx);
Run Code Online (Sandbox Code Playgroud)
第三种选择是在函数调用中隐藏强制转换:
void SetExtra(Context_T * ctx, void const * ext);
void * GetExtra(Context_T const * ctx);
Run Code Online (Sandbox Code Playgroud)
在这种情况下隐藏演员是个好主意吗?
我试图找到可用性和类型安全性的平衡点.但由于我们使用void*指针,很多安全性已经消失.
还是我忽略了值得考虑的事情?
C标准库有类似的问题.众所周知,该strchr函数接受一个const char *参数并返回一个char *指向给定字符串的值.
这是C语言的一个缺陷:它的规定const不支持const可以合理使用的所有方式.
遵循C标准的示例是不合理的:接受指向,const并且在将其返回给调用软件时,提供指向非标准的指针const,如在第三个示例中那样.
另一种方法是定义两组例程,SetExtra并且GetExtra在使用非const,和SetExtraConst与GetExtraConst该用途const.这些可以在运行时强制执行,并使用额外的位来记录设置的上下文是否const为非const.但是,即使没有强制执行,它们也可能会有所帮助,因为它们可以使调用代码中的错误更加明显:读取代码的人可以看到SetExtraConst用于设置数据和GetExtra(非const)用于获取数据.(如果调用代码有点复杂并且const在某些情况下使用数据而在其他情况下使用非const数据,这可能没有用,但最好是捕获更多错误而不是更少.)
| 归档时间: |
|
| 查看次数: |
188 次 |
| 最近记录: |