[英]dereferencing pointer to incomplete type in C
函数 getManager 创建一个 Manager 结构并从类型 ManagerP 返回一个指向它的指针(这个函数工作正常)。 定义是这样的:
typedef struct Manager
{
int ID;
char name[MAX_NAME_LENGTH];
int numberOfStudentsInSchool;
double paycheck;
double attract;
} Manager;
typedef struct Manager *ManagerP;
//My little code (that does the problem) is this (it's inside main):
int foundId;
ManagerP manToFind = getManager(1, "manager2", 200.0 , 1.0, 1000); //this works ok.
foundId = manToFind->ID; //Error : "dereferencing pointer to incomplete type"
你能帮我找到问题吗? 我不明白这个错误是什么意思。
谢谢。
编辑:
谢谢,但我刚刚注意到一个问题。 这些行在“Manager.c”中。
typedef struct Manager
{
int ID;
char name[MAX_NAME_LENGTH];
int numberOfStudentsInSchool;
double paycheck;
double attract;
} Manager;
typedef struct Manager *ManagerP;
在我的主文件中,我确实包含了具有更多定义的“Manager.h”。 我刚刚检查了一下,当我将两个 typedefs 代码(上面写的)移动到主文件时,一切正常。 但是我需要将这些 typedef 放在“Manager.c”中(然后我仍然收到“取消引用指向不完整类型的指针”错误。那么问题是什么??
编辑#2:好的,我正在发布这三个文件。 当我编译它们时,我收到错误:“GenSalary.c:9:21: 错误:取消引用指向不完整类型的指针”
这些是文件:
// * Manager.h * :
#ifndef MANAGER_H
#define MANAGER_H
#define MAX_NAME_LENGTH 30
typedef struct Manager *ManagerP;
ManagerP getManager(int ID, const char name[], double paycheck,
double attract, int numberOfStudentsInSchool);
#endif
// * Manager.c * :
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "Manager.h"
#define MAX_PRINT_LENGTH 1000
typedef struct Manager
{
int ID;
char name[MAX_NAME_LENGTH];
int numberOfStudentsInSchool;
double paycheck;
double attract;
} Manager;
ManagerP getManager(int ID, char const name[], double paycheck,
double attract, int numberOfStudentsInSchool)
{
ManagerP retVal = (ManagerP) malloc(sizeof(struct Manager));
if (retVal == NULL)
{
fprintf(stderr, "ERROR: Out of memory in Manager\n");
exit(1);
}
retVal->ID = ID;
strcpy(retVal->name, name);
retVal->paycheck = paycheck;
retVal->attract = attract;
retVal->numberOfStudentsInSchool = numberOfStudentsInSchool;
return retVal;
}
// * GenSalary.c * :
#include <stdio.h>
#include <stdlib.h>
#include "Manager.h"
int main()
{
int foundId;
ManagerP manToFind = getManager(1, "manager2", 200.0 , 1.0, 1000); //this works ok.
foundId = manToFind->ID; //Error : "dereferencing pointer to incomplete type"
return 0;
}
我使用 gcc -Wall GenSalary.c Manager.c -o GenSalary 编译它,我得到: GenSalary.c:9:21: 错误:解引用指向不完整类型的指针
注意:我无法更改管理器文件(它们属于锻炼)我只能更改主文件。
感谢您的帮助!
正如所写的那样, getManager
看起来像是希望返回的指针是不透明的。 如果是这种情况,通常会为调用者应该能够做的任何事情提供函数。 例如:
经理.h
...
typedef struct Manager *ManagerP;
ManagerP getManager(int ID, const char name[], double paycheck,
double attract, int numberOfStudentsInSchool);
int getManagerID(ManagerP);
经理.c
...
int getManagerID(ManagerP m) { return m->ID; }
gensalary.c
...
int foundId;
ManagerP manToFind = getManager(1, "manager2", 200.0 , 1.0, 1000);
foundId = getManagerID(manToFind);
另一种方法是将结构的定义移动到标题中,在那里一切都可以看到它(目前它是在标题中向前声明的,但只有manager.c知道里面是什么)。
下面的代码与gcc -Wall -pedantic -o test test.c
一起工作正常。 但是,我不确定使用typedef
隐藏指针类型对可读性有什么真正的好处。 错误必须来自代码上下文中的某个地方。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Manager
{
int ID;
char name[42];
int numberOfStudentsInSchool;
double paycheck;
double attract;
} Manager;
typedef struct Manager *ManagerP;
ManagerP getManager(int x, char *y, double z, double q, int p)
{
ManagerP foo = malloc(sizeof(Manager));
foo->ID = x;
strncpy(foo->name, y, 42);
foo->numberOfStudentsInSchool = p;
foo->paycheck = z;
foo->attract = q;
return foo;
}
int main(void)
{
int foundId;
ManagerP manToFind = getManager(1, "manager2", 200.0 , 1.0, 1000);
foundId = manToFind->ID;
printf("Found ID: %d\n", foundId);
return 0;
}
从您自己的编辑:
我刚刚检查了一下,当我将两个 typedefs 代码(上面写的)移动到主文件时,一切正常。 但是我需要将这些 typedef 放在“Manager.c”中
正如您所发现的,您需要包含这些定义才能使其工作。 将它们放在“Manager.h”中,并在主文件和“Manager.c”中包含“Manager.h”。
编辑:从你的代码,你需要包括typedef
在头文件中的实际结构,还有,不只是指针的类型定义,所以移动这个:
typedef struct Manager
{
int ID;
char name[MAX_NAME_LENGTH];
int numberOfStudentsInSchool;
double paycheck;
double attract;
} Manager;
从“Manager.c”中取出,放在 ManagerP 的 typedef 之前。 否则,主文件看到的只是指针的声明,它没有结构实际包含什么的信息,因此你会得到“不完整的类型”错误。
编辑 2:如果您说“无法更改管理器文件”,那么这是一个有点愚蠢的问题,因为您无法应用最佳答案,但如果确实如此,那么您将只需要将结构定义复制并粘贴到“GenSalary.c”中(或粘贴到用户创建的新头文件中,如果您也需要在其他文件中使用它),因为该文件需要它。 由于很多原因,在“GenSalary.c”和“Manager.c”中分别定义结构是一个坏主意,但它是完全合法的 C,并且它会工作(这就是当你#include
时发生的所有事情一个头文件,无论如何)。
为 ManagerP 执行 typedef 的行将编译,因为它是一个指针声明,但是由于结构管理器在文件 Manager.c 中并且对 GenSalary.c 不可用,编译器无法知道结构管理器是什么样子。
所以包含文件Manager.h需要有以下几行代码。
typedef struct Manager
{
int ID;
char name[MAX_NAME_LENGTH];
int numberOfStudentsInSchool;
double paycheck;
double attract;
} Manager;
typedef struct Manager *ManagerP;
然后,任何包含 Manager.h 的源文件都将具有 Manager typedef 和 ManagerP typedef 的定义。 当 ManagerP 被取消引用时,编译器将知道如何访问 Manager 结构的各个部分。
编辑:其他注意事项
你提到这是某种形式的练习,所以我想指出这是完成的方式,文件中的结构和唯一暴露的是指向结构的指针,是一种经常用于隐藏结构细节的机制. 这种技术的目标是提供一个指向库中对象的指针,在这种情况下是结构,但是使用库的人不会访问任何结构成员或做任何事情,而不是将指针传递给其他函数在图书馆里。
因此,本练习的重点可能是不访问任何结构成员。
创建指向类型的指针时,编译器不需要知道该类型是什么样的,因为所有指针的大小都相同(4 或 8 或多少字节)。 但是,如果您尝试取消引用该指针,则编译器必须知道该类型是什么样的,以便计算内存偏移量并执行其他任务。 由于在您的原始 cpp 文件中,类型Manager
未定义,仅声明为,因此编译器无法确定在到达ID
字段之前需要使用的内存偏移量。 (这样的类型通常称为opaque 。)因此编译器会通知您该类型是不完整的。
如果您尝试直接创建类型为Manager
的变量,则会出现同样的问题,因为编译器不知道需要为该变量留出多少内存。 你可以malloc
一个指针Manager
,但如果你试图做sizeof(Manager)
,它会失败。
为了使其工作,编译器需要知道在您尝试取消引用指针时的类型是什么样的。 因此,结构体定义必须放置在主 cpp 文件中,或者放置在该 cpp 文件包含的任何头文件中。
当我回到家时,我将解决这个问题,这看起来很有趣!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.