是否值得更改 C 声明以增加类型安全性?

Is it worthwhile changing a C declaration to add type safety?

我想知道覆盖 header 声明以设置特定类型是否合理或值得。优先于 void * 之类的东西,它不增加类型安全性。

例如,如果您有一个将传感器读数添加到循环缓冲区的通用存储函数:

int add_reading(void *);

为了通用,函数必须定义为 void *。但是,在 header 文件中,您可以将函数声明为:

int add_reading(my_reading_t *);

这将在 void 指针上增加一定程度的类型安全性。在通用 header 中,您可以使用默认为 void 的 #define 设置类型。因此覆盖类型可以在 #include.

之前定义

这似乎是一种不必要的 hack,但对于不透明指针也可以争论同样的问题——使用 opaque_type_t * 而不是 void *。但这至少是定义的行为。我想知道的是这种混乱是否会调用 UB(未定义的行为)?

你的建议看起来不是个好主意。如果你想提高类型安全性,如果你试图传入错误的类型就无法编译,你可以尝试使用 C11 的 _Generic.

int add_reading (void *);
#define ADD_READING_HELPER(X) _Generic((X), \
    my_reader_t *: add_reading((X)) \
)

int main(void) {
    my_reader_t good;
    printf("%d\n", ADD_READING_HELPER(&good)); // works because _Generic has a rule for dealing with (my_reader_t *)
    int bad;
    printf("%d\n", ADD_READING_HELPER(&bad)); // fails to compile because the _Generic does not have a rule for dealing with (int *)
}

int add_reading (void *arg) {
    // whatever the function does
}

本质上 _Generic 允许您根据传递给它的表达式的控制类型执行不同的操作,这都是在编译时确定的。我们在这里做的是为 my_reader_t * 创建规则,但没有其他类型,因此尝试将 my_reader_t * 以外的任何内容传递给 _Generic 将阻止程序编译,因为它不会'对如何处理该类型有任何规则。

int add_reading(void *) 声明的函数与用 int add_reading(my_reading_t *) 定义的函数不兼容。根据 C 2018 6.5.2.2 9:

,C 标准不会定义使用用前者声明的标识符(或具有该类型的其他函数指示符)调用用后者定义的函数的行为

If the function is defined with a type that is not compatible with the type (of the expression) pointed to by the expression that denotes the called function, the behavior is undefined.

根据 6.7.6.1 2:

For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.

显然,参数类型void *my_reading_t *不是指向兼容类型的指针(假设my_reading_t是结构类型,不是void的别名) .

根据 6.7.6.3 15:

For two function types to be compatible,… corresponding parameters shall have compatible types…