在定义不透明指针时防止不完整的类型声明?



C标准中有一个功能隐藏了我代码中的一个bug,我想知道是否有一些方法可以防止它,或者至少发出警告。

在C语言中,这段代码隐式地将struct foo声明为不完整类型:

struct foo *ptr; /* I didn't even tell the compiler I wish to use struct foo */

然而,我更希望被要求声明不完整类型,像这样:

struct foo; /* foo is incomplete, but I'm telling the compiler to allow references to foo */
struct foo *ptr; /* that's fine, pointer to an incomplete type which I said I wish to use */

我说的错误是我在指针定义中打了一个错字,所以它指向一个"匆忙"创建的不完整类型。编译器在没有警告的情况下。如果编译器警告我"指针指向未声明的结构"之类的东西,我就会纠正这个错字。我能以某种方式启用这样的警告吗?

指针本身是可以的,只要您不解引用它或以需要完整类型的方式使用它。

如果你尝试,你会得到一个错误。

例子:

struct foo; /* foo is incomplete, but I'm telling the compiler to allow references to foo */
void foo(void *vptr)
{
struct foo *ptr = ptr;
ptr -> x = 0; //error
}
#include <stdlib.h>
struct foo; /* foo is incomplete, but I'm telling the compiler to allow references to foo */
void foo(void)
{
struct foo *ptr = malloc(sizeof(*ptr)); // error - incomplete type 
}

https://godbolt.org/z/bnKEGr

不需要额外的警告消息,因为指向不完整类型的指针是有效的。

不能分配不完整类型的对象,除非该定义与变量出现在相同的翻译单元中。这就是使用不透明指针的全部意义——类型是由相应的。c文件中的结构定义完成的,而调用者是不可见的。

有两种实现方法,一种是在不带指针的头文件中定义类型:

typedef struct foo foo;

或作为指针:

typedef struct foo* foo;

前一种风格的优点是不会将指针隐藏在typedef后面,这通常会令人困惑。例如,你的API是void foo_init (foo* f);,调用者必须将所有实例声明为指针。

后一种风格的优点是,您可以假装不透明类型是一个公共变量。这允许调用者表面上声明对象,而实际上他们在没有意识到的情况下声明指针。API变成了void foo_init (foo f);,其中所有内容似乎都是通过值传递的。

你的错误的问题是,你可以在代码的任何地方打错字,编译器无法知道你是否将最终完成类型(它是有效的不完成类型,有一些用途,如不透明类型)

不透明类型通常由引用管理,您定义一个不完整的结构,并在公共头文件中导出,并在私有头文件中完成。实现模块包括两个文件(仅包括私有文件,但由于私有文件将包括公共文件,因此您将同时拥有两个文件),库用户只包括公共文件,其中包含不完整文件。通过这种方式,您可以管理一个不知道其内部结构的对象库,但实现可以完全访问它们。由于指向不同结构的指针是不同类型的指针,因此需要进行弱类型检查。

但是所有这些都要求编译器在到达一个编译单元的末尾时关闭,并且一些类型还没有完成。

最新更新