为用户数据选择const与非const指针

use*_*733 2 c api

考虑一个简单,可重用的库.它有一个当前状态的对象,以及一个回调函数来输入它.

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*指针,很多安全性已经消失.

还是我忽略了值得考虑的事情?

Eri*_*hil 5

C标准库有类似的问题.众所周知,该strchr函数接受一个const char *参数并返回一个char *指向给定字符串的值.

这是C语言的一个缺陷:它的规定const不支持const可以合理使用的所有方式.

遵循C标准的示例是不合理的:接受指向,const并且在将其返回给调用软件时,提供指向非标准的指针const,如在第三个示例中那样.

另一种方法是定义两组例程,SetExtra并且GetExtra在使用非const,和SetExtraConstGetExtraConst该用途const.这些可以在运行时强制执行,并使用额外的位来记录设置的上下文是否const为非const.但是,即使没有强制执行,它们也可能会有所帮助,因为它们可以使调用代码中的错误更加明显:读取代码的人可以看到SetExtraConst用于设置数据和GetExtra(非const)用于获取数据.(如果调用代码有点复杂并且const在某些情况下使用数据而在其他情况下使用非const数据,这可能没有用,但最好是捕获更多错误而不是更少.)

  • `strchr`的constness问题有一个更简单的解决方案:只返回字符串开头的偏移量.我喜欢认为这是'strchr`所做的事情,而不是在`const`之前发明的. (2认同)