取消引用指向不完整类型的指针

Posted

技术标签:

【中文标题】取消引用指向不完整类型的指针【英文标题】:dereferencing pointer to incomplete type 【发布时间】:2011-02-11 15:21:42 【问题描述】:

我已经看到了很多关于此的问题,但我将在没有特定代码的情况下提出不同的问题。有没有办法轻松确定导致类型不完整的原因?在我的情况下,我使用的是别人的代码,我完全确定我没有正确的标题,但是(因为计算机比人类眼球更快更好地完成这些工作)有没有办法让编译器说,“嘿,您认为您在第 34 行输入了 X,但实际上 缺少。”错误本身仅在您分配时显示,这不是很有帮助。

【问题讨论】:

【参考方案1】:

我不完全理解问题所在。不完整类型不是“缺失”的类型。不竞争类型是已声明但未定义的类型(在结构类型的情况下)。找到非定义声明很容易。至于找到缺少的定义......编译器不会在这里帮助你,因为这是首先导致错误的原因。

C 中不完整类型错误的一个主要原因是类型名称中的拼写错误,这会阻止编译器将一个名称与另一个名称匹配(例如将声明与定义匹配)。但同样,编译器在这里无法为您提供帮助。编译器不会猜测错别字。

【讨论】:

【参考方案2】:

你的意思是,错误只在你分配时出现?例如在 GCC 上,看不到任务:

int main() 
    struct blah *b = 0;
    *b; // this is line 6

incompletetype.c:6: error: dereferencing pointer to incomplete type.

错误 is 在第 6 行,这就是我使用不完整类型的地方,就好像它是完整类型一样。在那之前我都很好。

错误是您应该包含定义类型的任何标题。但是编译器不可能猜到应该包含在哪一行:函数之外的任何行都可以,差不多。它也不会遍历系统上的每个文本文件,寻找定义它的标题,并建议你应该包含它。

或者(好点,potatoswatter),错误出现在定义b 的行,当您意味着指定某些实际存在的类型,但实际上指定了blah。在大多数情况下,查找变量b 的定义应该不会太难。 IDE 通常可以为您完成,编译器警告可能不会被打扰。但是,如果您找不到所用事物的定义,那将是一些非常令人发指的代码。

【讨论】:

【参考方案3】:

前几天我看到一个问题,有人通过指定类似的东西无意中使用了不完整的类型

struct a 
    int q; 
; 
struct A *x; 
x->q = 3;

编译器知道struct A 是一个结构,尽管A 是完全未定义的,但由于struct 关键字。

那是在 C++ 中,struct 的这种用法是非典型的(而且,事实证明,可能会导致踢脚)。如果你这样做,在 C 中

typedef struct a 
    ...
 a;

然后您可以使用a 作为类型名,稍后省略struct。如果您输入错误名称或忘记标题,这将导致编译器稍后给您一个未定义的标识符错误,而不是不完整的类型。

【讨论】:

【参考方案4】:

这个错误通常显示你的结构的名称是否与代码中结构的初始化不同,所以通常,c会找到你放置的结构的名称,如果没有找到原始结构,这通常会出现,或者如果您指向指向该指针的指针,则会出现错误。

【讨论】:

同意。首先检查结构定义与声明中的拼写错误,以及任何类型定义。【参考方案5】:

A - 解决方案

对于 C 语言,我刚刚发现以下声明代码将是解决方案;

typedef struct ListNode

    int data;
    ListNode * prev;
    ListNode * next;
 ListNode;

因此,作为一般规则,我为类型定义和结构名称提供相同的名称;

typedef struct X

    // code for additional types here
    X* prev; // reference to pointer
    X* next; // reference to pointer
 X;

B - 有问题的样本

在执行以下语句时,gcc 编译器认为以下声明均不完整。 ;

removed->next->prev = removed->prev;

对于错误输出中报告的取消引用代码,我得到相同的错误;

>gcc Main.c LinkedList.c -o Main.exe -w
LinkedList.c: In function 'removeFromList':
LinkedList.c:166:18: error: dereferencing pointer to incomplete type 'struct ListNode'
     removed->next->prev = removed->prev;

对于下面列出的两个头文件声明;

typedef struct

    int data;
    ListNode * prev;
    ListNode * next;
 ListNode;

加上这个;

typedef struct ListNodeType

    int data;
    ListNode * prev;
    ListNode * next;
 ListNode;

【讨论】:

【参考方案6】:

在涉及整个程序优化的可能场景之外,生成的代码代码如下:

struct foo *bar;
struct foo *test(struct foo *whatever, int blah)

  return blah ? whatever: bar;

将完全不受struct foo 可能包含的成员的影响。因为 make 实用程序通常会重新编译出现完整结构定义的任何编译单元,即使这些更改实际上不会影响为它们生成的代码,通常会从实际上不需要的编译单元中省略完整的结构定义他们,这样的遗漏通常不值得警告。

编译器需要具有完整的结构或联合定义,以了解如何处理具有自动或静态持续时间的类型的声明对象、包含该类型成员的聚合声明或访问结构或联合成员的代码。如果编译器没有执行上述操作之一所需的信息,它将别无选择,只能大声疾呼。

顺便说一下,还有一种情况,标准允许编译器要求完整的联合定义可见但不需要诊断:如果两个结构以通用初始序列开头,并且包含两者的联合类型可见当编译器正在处理使用其中一种结构类型的指针来检查该公共初始序列的成员的代码时,编译器需要识别此类代码可能正在访问另一种类型的结构的相应成员。我不知道哪些编译器在完整联合类型可见但不可见时是否符合标准 [gcc 在任何一种情况下都容易生成不符合标准的代码,除非使用 -fno-strict-aliasing 标志,在在这种情况下,它将在两种情况下都生成符合标准的代码] 但是如果想要编写使用 CIS 规则的代码,以保证符合标准的编译器的正确行为,则可能需要确保完整的联合类型定义是可见的;否则可能会导致编译器默默地生成虚假代码。

【讨论】:

【参考方案7】:

另一个可能的原因是间接引用。如果代码引用了当前 c 文件中未包含的结构,编译器会报错。

a->b->c //如果 b 不包含在当前 c 文件中则错误

【讨论】:

以上是关于取消引用指向不完整类型的指针的主要内容,如果未能解决你的问题,请参考以下文章

取消引用指向不完整类型的指针

C错误 - 取消引用指向不完整类型的指针

取消引用指向整个数组的指针

指向不完整类型的指针可以不完整吗?

删除时出错:表达式必须是指向完整对象类型的指针

“不允许指向不完整类类型的指针”