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

时间:2010-04-23 17:32:32

标签: c struct compiler-errors typedef dereference

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

7 个答案:

答案 0 :(得分:46)

前几天我看到一个问题,有人通过指定

这样的东西而无意中使用了不完整的类型
struct a {
    int q; 
}; 
struct A *x; 
x->q = 3;

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

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

typedef struct a {
    ...
} a;

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

答案 1 :(得分:10)

你是什么意思,错误只会在你分配时出现?例如,在海湾合作委员会,没有任何指配:

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

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

第6行的错误,这就是我使用不完整类型的地方,就像它是一个完整的类型一样。直到那时我还好。

错误在于您应该包含定义类型的任何标头。但是编译器无法猜测应该包含哪一行:函数外的任何行都可以。它也不会拖网浏览你系统上的每个文本文件,寻找定义它的标题,并建议你应该包括它。

或者(好点,potatoswatter),错误位于定义b的行,当意味着指定实际存在的某种类型,但实际指定{{1 }}。在大多数情况下,查找变量blah的定义应该不会太困难。 IDE通常可以为您完成,编译器警告可能无法打扰。但是,如果你找不到你正在使用的东西的定义,这是一些非常令人发指的代码。

答案 2 :(得分:8)

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

  

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

答案 3 :(得分:7)

我并不完全明白这是什么问题。不完整类型不是“缺失”的类型。 Incompete类型是声明但不是定义的类型(在结构类型的情况下)。要找到非定义声明很容易。至于找到缺少的定义......编译器在这里没有帮助,因为这是导致错误的原因。

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

答案 4 :(得分:1)

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

答案 5 :(得分:0)

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 :(得分:0)

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

struct foo *bar;
struct foo *test(struct foo *whatever, int blah)
{
  return blah ? whatever: bar;
}

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

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

顺便提一下,还有一种情况,即标准允许编译器要求完整的联合定义可见但不需要诊断:如果两个结构以公共初始序列和联合类型开头当编译器处理使用其中一种结构类型的指针来检查该公共初始序列的成员的代码时,包含两者的内容是可见的,编译器需要认识到这样的代码可能正在访问该结构的相应成员。其他类型。当完整的联合类型可见时,我不知道编译器是否符合标准,但是当它不是[gcc在任何一种情况下都容易产生不符合代码时],除非{{1}使用} flag,在这种情况下它将在两种情况下生成符合规范的代码]但是如果想要编写使用CIS规则的代码以保证符合编译器的正确行为,可能需要确保完全联合类型定义是可见的;如果不这样做,可能会导致编译器静默生成虚假代码。