繁体   English   中英

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

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM