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

时间:2013-10-07 13:24:53

标签: 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

用户可能需要一些额外的数据用于回调(如文件指针)。图书馆 提供了一个额外指针的函数:

void SetExtra(Context_T * ctx, void * ext); // May be called after init
void * GetExtra(Context_T const * ctx); // May be called in callback

但是,如果用户额外数据是常量,则需要他强制转换constness 在设置数据之前离开。我可以改变函数来取/返const, 但如果数据不应该是常数,这将需要在回调中额外投射。

void SetExtra(Context_T * ctx, void const * ext);
void const * GetExtra(Context_T const * ctx);

第三种选择是在函数调用中隐藏强制转换:

void SetExtra(Context_T * ctx, void const * ext);
void * GetExtra(Context_T const * ctx);

在这种情况下隐藏演员是否是个好主意?

我正试图找到可用性和类型安全性的平衡点。但既然我们是 使用void*指针,很多安全措施已经消失。

或者我忽略了值得考虑的事情?

2 个答案:

答案 0 :(得分:5)

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

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

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

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

答案 1 :(得分:1)

对于标准的“hack away”功能程序设计,它非常简单:

  • 如果函数修改指针参数的内容,则指针不应为const。
  • 如果函数不修改指针参数的内容,则指针应始终为const。

但在您的情况下,您似乎正在进行适当的面向对象设计,其中您的代码模块是唯一知道Context_T是什么以及它包含什么的人。 (我认为第一行的typedef实际上是在h文件中?)

如果是这样,你不能也不应该指针const。特别是如果你使用不完整类型(“opaque”类型)实现真正的OO封装,因为在这种情况下调用者无论如何都不能修改内容:“const correctness”变得多余。