我已经看到了很多关于此的问题,但我将在没有特定代码的情况下以不同的方式提出问题。有没有办法轻松确定导致类型不完整的原因?在我的情况下,我使用的是其他人的代码,我完全确定我没有正确的标题,但是(因为计算机比人类的眼球更快更好地完成这些事情)有没有办法让编译器说, “嘿,你认为你在第 34 行输入了 X,但实际上没有。” 错误本身仅在您分配时才出现,这不是很有帮助。
7 回答
前几天我看到一个问题,有人通过指定类似的东西无意中使用了不完整的类型
struct a {
int q;
};
struct A *x;
x->q = 3;
编译器通过关键字知道这struct A
是一个结构,尽管它完全未定义。A
struct
那是在 C++ 中,这种用法struct
是非典型的(而且,事实证明,可能会导致踢脚)。如果你这样做,在 C 中
typedef struct a {
...
} a;
然后您可以a
用作类型名并省略struct
后面的内容。如果您输入错误名称或忘记了标题,这将导致编译器稍后给您一个未定义的标识符错误,而不是不完整的类型。
另一个可能的原因是间接引用。如果代码引用了当前 c 文件中未包含的结构,编译器会报错。
a->b->c //如果 b 不包含在当前 c 文件中,则错误
你是什么意思,错误只在你分配时出现?例如在 GCC 上,看不到分配:
int main() {
struct blah *b = 0;
*b; // this is line 6
}
incompletetype.c:6: error: dereferencing pointer to incomplete type
.
错误在第 6 行,在那里我使用了一个不完整的类型,就好像它是一个完整的类型一样。在那之前我都很好。
错误是您应该包含定义类型的任何标题。但是编译器不可能猜到应该包含在哪一行:函数之外的任何行都可以,差不多。它也不会遍历系统上的每个文本文件,寻找定义它的标题,并建议您应该包含它。
或者(好点,potatoswatter),错误出现在b
定义的行,当您打算指定一些实际存在但实际指定的类型时blah
。在大多数情况下,找到变量的定义b
应该不会太难。IDE 通常可以为您完成,编译器警告可能不会被打扰。但是,如果您找不到正在使用的东西的定义,那将是一些非常令人发指的代码。
我不完全明白是什么问题。不完整类型不是“缺失”的类型。不竞争类型是已声明但未定义的类型(在结构类型的情况下)。找到非定义声明很容易。至于找到缺少的定义......编译器在这里不会帮助你,因为这首先是导致错误的原因。
C 中不完整类型错误的一个主要原因是类型名称中的拼写错误,这会阻止编译器将一个名称与另一个名称匹配(例如将声明与定义匹配)。但同样,编译器在这里无法为您提供帮助。编译器不会猜测错别字。
此错误通常显示您的结构的名称是否与代码中结构的初始化不同,因此通常c会找到您放置的结构的名称,如果找不到原始结构,通常会出现这种情况,或者如果您指向指向该指针的指针,则会显示错误。
一个办法
说到 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;
在涉及整个程序优化的可能场景之外,生成的代码代码如下:
struct foo *bar;
struct foo *test(struct foo *whatever, int blah)
{
return blah ? whatever: bar;
}
将完全不受成员struct foo
可能包含的内容的影响。因为 make 实用程序通常会重新编译出现结构完整定义的任何编译单元,即使这些更改实际上不会影响为它们生成的代码,通常会从实际上不需要的编译单元中省略完整的结构定义他们,这种遗漏通常不值得警告。
编译器需要具有完整的结构或联合定义,以了解如何处理具有自动或静态持续时间的类型的声明对象、包含该类型成员的聚合声明或访问结构或联合成员的代码。如果编译器没有执行上述操作之一所需的信息,它将别无选择,只能大声疾呼。
顺便说一下,还有另一种情况,标准允许编译器要求完整的联合定义可见但不需要诊断:如果两个结构以公共初始序列开头,并且包含两者的联合类型在编译器时可见正在处理使用其中一种结构类型的指针来检查该公共初始序列的成员的代码,编译器需要识别此类代码可能正在访问另一种类型的结构的相应成员。我不知道哪些编译器在完整联合类型可见但不可见时符合标准 [gcc 在任何一种情况下都容易生成不符合标准的代码,除非-fno-strict-aliasing
使用标志,在这种情况下,它将在两种情况下都生成符合要求的代码] 但是如果想要编写使用 CIS 规则的代码,以保证符合标准的编译器的正确行为,则可能需要确保完整的联合类型定义可见;不这样做可能会导致编译器默默地生成虚假代码。