【发布时间】:2019-07-12 08:16:05
【问题描述】:
我想知道为了设置特定类型而重写标题声明是否合理或值得。优先于 void * 之类的东西,它不会增加类型安全性。
例如,如果您有一个通用存储函数,它将传感器读数添加到循环缓冲区:
int add_reading(void *);
为了通用,函数必须定义为 void *。但是,在头文件中,您可以将函数声明为:
int add_reading(my_reading_t *);
这将在 void 指针上增加一定程度的类型安全性。在通用标头中,您可以使用默认为 void 的 #define 设置类型。因此可以在#include 之前定义覆盖类型。
这似乎是一种不必要的 hack,但是对于不透明指针也可以这样争论——使用 opaque_type_t * 而不是 void *。但这至少是定义的行为。我想知道这种类型的混乱是否会调用 UB(未定义的行为)?
【问题讨论】:
-
如果你打算在你的标题之前有一个
#define#include,那么我认为这是一个非常糟糕的主意。不是最具可扩展性的概念。如果你想在同一个文件中使用不同类型的函数怎么办? -
呃。您是对的 - 代码中确实存在一个基本假设,即该函数仅用于一种类型。实际上有一条评论“只有其中一个,所以本地静态结构保持状态”:-)
-
如果你有一个通用函数,你可能应该传递你正在操作的任何东西的大小以及指向数据的指针。除非,也许,您存储的是指针本身,而没有对其进行任何解释。我会选择类型安全的覆盖函数:
static inline int add_my_reading(my_reading_t *r) { return add_reading(r); }就足够了(假设您只存储指针并且不需要大小)。对于每种不同的类型,您可能还需要不同的循环缓冲区,在这种情况下,接口需要更多的升级工作,以包含“环形缓冲区句柄指针”。 -
DeiDei的评论是正确答案。这不是一个可扩展的概念。它实际上是在一个地方使用的代码,现在在多个地方使用 - 这意味着它应该正确编写或复制/粘贴并单独调整。不是半途而废。我很懒...
-
如果你小心的话,你的头部可以定义覆盖函数,并在后面加上
#define add_reading(r) do not call add_reading directly,以防止意外使用原始函数。就目前而言,有人可以故意使用:(add_reading)(r);会调用原始函数,尽管有类似函数的宏。使用#define add_reading do not use add_reading directly也可以防止这种误用。#undef仍然可以使用——但有一点是你试图防止恶意而不是意外,最好让编码人员遵守手册和规则。
标签: c type-conversion header-files void-pointers