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

C 在定义不透明指针时防止不完整的类型声明?,c,C,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 a

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
}
#包括
结构foo;/*foo不完整,但我告诉编译器允许对foo的引用*/
无效foo(无效)
{
struct foo*ptr=malloc(sizeof(*ptr));//错误-类型不完整
}


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

除非定义与变量位于同一转换单元中,否则不能分配不完整类型的对象。这就是使用不透明指针的全部要点——类型由相应的.c文件中的结构定义完成,调用方将看不到它

有两种方法可以实现它们,一种是在没有指针的标题中作为typedef:

typedef struct foo foo;
或作为指针:

typedef struct foo* foo;
前一种样式的优点是不会将指针隐藏在typedef后面,这通常会让人困惑。然后,您的API将是例如
void foo_init(foo*f),调用方必须将所有实例声明为指针


后一种样式的优点是,您可以假装不透明类型是一个公共变量。这允许调用者表面上声明对象,而实际上他们在声明指针时却没有意识到。然后API变为
void foo_init(foo f)所有内容似乎都是按值传递的。

错误的问题在于,您可以在代码中的任何位置键入,编译器无法知道您是否最终将完成该类型(不完成该类型是有效的,它有一些用途,例如不透明类型)

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


但所有这些都要求编译器在到达编译单元末尾时关闭,并且某些类型尚未完成。

想法:使用typedef。如果尝试取消引用它,则会出现错误。“它指向一个不完整的类型,该类型是由编译器“动态”创建的,没有任何警告。”这是什么意思?编译器不允许您创建不完整类型的实际对象。(忽略任何编译器错误)很难理解为什么不完整类型的隐式声明会是一个问题。什么类型的错误?除非强制转换,否则不能将此指针用于没有输入错误的函数。也许是强制转换隐藏了错误?键入错误的结构名称可能是错误的,但它本身不会导致程序失败。例如,如果我使用
structfoo*p;外部结构foo*getting(void);外部无效使用(结构foo*);使用(GetThing())GetThing
UseThing
使用
struct bar
在另一个模块中,这将在C中工作(由于一些关于结构指针互换性的要求)。那么,您的程序中有什么不起作用?如果你告诉我们,我们可能会提出一些检测方法。
typedef struct foo* foo;