简体   繁体   English

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

[英]dereferencing pointer to incomplete type in C

The function getManager creates a Manager struct and returns a pointer to it from the type ManagerP (This function works ok).函数 getManager 创建一个 Manager 结构并从类型 ManagerP 返回一个指向它的指针(这个函数工作正常)。 The definitions are like this :定义是这样的:

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"

Can you please help me finding the problem ?你能帮我找到问题吗? I don't understand what this error mean.我不明白这个错误是什么意思。

Thanks.谢谢。


EDIT:编辑:

Thanks but I just noticed a problem.谢谢,但我刚刚注意到一个问题。 These lines are inside "Manager.c".这些行在“Manager.c”中。

typedef struct Manager
{
    int ID;
    char name[MAX_NAME_LENGTH];
    int numberOfStudentsInSchool;
    double paycheck;
    double attract;
} Manager;
typedef struct Manager *ManagerP;

In my main file I do include "Manager.h" that has some more definitions.在我的主文件中,我确实包含了具有更多定义的“Manager.h”。 I just checked and when I'm moving the two typedefs code (written above) to the main file, everything works properly.我刚刚检查了一下,当我将两个 typedefs 代码(上面写的)移动到主文件时,一切正常。 But I need these typedefs to be inside "Manager.c" (and then I still get a "dereferencing pointer to incomplete type" error. So what is the problem ??但是我需要将这些 typedef 放在“Manager.c”中(然后我仍然收到“取消引用指向不完整类型的指针”错误。那么问题是什么??

Edit #2 : Ok I'm posting the three files.编辑#2:好的,我正在发布这三个文件。 When I compile those I get the error : "GenSalary.c:9:21: error: dereferencing pointer to incomplete type"当我编译它们时,我收到错误:“GenSalary.c:9:21: 错误:取消引用指向不完整类型的指针”

These are the files :这些是文件:

// * Manager.h * : // * 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 * : // * 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 * : // * 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;
}

I compile it using gcc -Wall GenSalary.c Manager.c -o GenSalary and i'm getting : GenSalary.c:9:21: error: dereferencing pointer to incomplete type我使用 gcc -Wall GenSalary.c Manager.c -o GenSalary 编译它,我得到: GenSalary.c:9:21: 错误:解引用指向不完整类型的指针

NOTE : I CAN'T CHANGE THE MANAGER FILES (THEY BELONG TO EXERCISE)I CAN CHANGE ONLY MAIN.注意:我无法更改管理器文件(它们属于锻炼)我只能更改主文件。

Thanks for helping !感谢您的帮助!

As written, getManager looks like it intends the returned pointer to be opaque.正如所写的那样, getManager看起来像是希望返回的指针是不透明的。 If that is the case, it would be usual to provide functions for anything the caller should be able to do.如果是这种情况,通常会为调用者应该能够做的任何事情提供函数。 For example:例如:

manager.h经理.h

...
typedef struct Manager *ManagerP;

ManagerP getManager(int ID, const char name[], double paycheck, 
                    double attract, int numberOfStudentsInSchool);
int getManagerID(ManagerP);

manager.c经理.c

...
int getManagerID(ManagerP m) { return m->ID; }

gensalary.c gensalary.c

...
int foundId;
ManagerP manToFind = getManager(1, "manager2", 200.0 , 1.0, 1000);
foundId = getManagerID(manToFind);

The alternative is to move the definition of your struct into the header, where everything can see it (at the moment it is forward-declared in the header, but only manager.c know what is inside).另一种方法是将结构的定义移动到标题中,在那里一切都可以看到它(目前它是在标题中向前声明的,但只有manager.c知道里面是什么)。

The code below works fine with gcc -Wall -pedantic -o test test.c .下面的代码与gcc -Wall -pedantic -o test test.c一起工作正常。 I am unsure, however, that hiding pointer types using typedef s has any real advantages to readability.但是,我不确定使用typedef隐藏指针类型对可读性有什么真正的好处。 The error must come from somewhere in the context of your code.错误必须来自代码上下文中的某个地方。

#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;
}

From your own edit:从您自己的编辑:

I just checked and when I'm moving the two typedefs code (written above) to the main file, everything works properly.我刚刚检查了一下,当我将两个 typedefs 代码(上面写的)移动到主文件时,一切正常。 But I need these typedefs to be inside "Manager.c"但是我需要将这些 typedef 放在“Manager.c”中

You need to include these definitions for it to work, as you've found.正如您所发现的,您需要包含这些定义才能使其工作。 Put them in "Manager.h" and include "Manager.h" in both your main file, and in "Manager.c".将它们放在“Manager.h”中,并在主文件和“Manager.c”中包含“Manager.h”。

EDIT: From your code, you need to include the typedef of the actual struct in the header file, as well, not just the typedef of the pointer, so move this:编辑:从你的代码,你需要包括typedef在头文件中的实际结构,还有,不只是指针的类型定义,所以移动这个:

typedef struct Manager
{
int ID;
char name[MAX_NAME_LENGTH];
int numberOfStudentsInSchool;
double paycheck;
double attract;
} Manager;  

out of "Manager.c", and put it immediately before the typedef of ManagerP.从“Manager.c”中取出,放在 ManagerP 的 typedef 之前。 Otherwise, all the main file sees is the declaration of the pointer, and it has no information of what the struct actually contains, hence the "incomplete type" error you're getting.否则,主文件看到的只是指针的声明,它没有结构实际包含什么的信息,因此你会得到“不完整的类型”错误。

EDIT 2: If you "CAN'T CHANGE THE MANAGER FILES" as you say, then it's a bit of a silly question, since you can't apply the best answer, but if that actually is true, then you'll just have to copy and paste the struct definition into "GenSalary.c" (or into a new, user-created header file, if you need to use it in other files, too), because that file needs it.编辑 2:如果您说“无法更改管理器文件”,那么这是一个有点愚蠢的问题,因为您无法应用最佳答案,但如果确实如此,那么您将只需要将结构定义复制并粘贴到“GenSalary.c”中(或粘贴到用户创建的新头文件中,如果您也需要在其他文件中使用它),因为该文件需要它。 Defining the struct separately in both "GenSalary.c" and "Manager.c" is a bad idea for lots of reasons, but it is perfectly legal C, and it'll work (that's all that's happening under the hood when you #include a header file, anyway).由于很多原因,在“GenSalary.c”和“Manager.c”中分别定义结构是一个坏主意,但它是完全合法的 C,并且它会工作(这就是当你#include时发生的所有事情一个头文件,无论如何)。

The line of doing the typedef for ManagerP will compile since it is a pointer declaration however since the struct Manager is in the file Manager.c and is not available to GenSalary.c the compiler is unable to know what the struct Manager looks like.为 ManagerP 执行 typedef 的行将编译,因为它是一个指针声明,但是由于结构管理器在文件 Manager.c 中并且对 GenSalary.c 不可用,编译器无法知道结构管理器是什么样子。

So the include file Manager.h needs to have the following lines of code.所以包含文件Manager.h需要有以下几行代码。

typedef struct Manager
{
int ID;
char name[MAX_NAME_LENGTH];
int numberOfStudentsInSchool;
double paycheck;
double attract;
} Manager;

typedef struct Manager *ManagerP;

Then any source file that includes Manager.h will have the definition of the Manager typedef as well as the ManagerP typedef.然后,任何包含 Manager.h 的源文件都将具有 Manager typedef 和 ManagerP typedef 的定义。 And when the ManagerP is dereferenced, the compiler will know how to access the various parts of the Manager struct.当 ManagerP 被取消引用时,编译器将知道如何访问 Manager 结构的各个部分。

Edit: Other considerations编辑:其他注意事项

You mention that this is an exercise of some kind so I would like to note that the way this is being done, the struct in a file and the only thing exposed is a pointer to the struct, is a mechanism often used to hide struct details.你提到这是某种形式的练习,所以我想指出这是完成的方式,文件中的结构和唯一暴露的是指向结构的指针,是一种经常用于隐藏结构细节的机制. The goal of this technique is to provide a pointer to an object within a library, the struct in this case, however the person using the library is not to access any of the struct members or to do anything other than pass the pointer to other functions in the library.这种技术的目标是提供一个指向库中对象的指针,在这种情况下是结构,但是使用库的人不会访问任何结构成员或做任何事情,而不是将指针传递给其他函数在图书馆里。

So it may be that the point of this exercise is to not access any of the struct members.因此,本练习的重点可能是不访问任何结构成员。

When you create a pointer to a type, the compiler does not need to know what that type looks like, because all pointers are the same size (4 or 8 or however many bytes).创建指向类型的指针时,编译器不需要知道该类型是什么样的,因为所有指针的大小都相同(4 或 8 或多少字节)。 However, if you attempt to dereference that pointer, the compiler must know what the type looks like in order to calculate memory offsets and perform other tasks.但是,如果您尝试取消引用该指针,则编译器必须知道该类型是什么样的,以便计算内存偏移量并执行其他任务。 Since in your original cpp file the type Manager is not defined, only declared , the compiler cannot determine what memory offset it needs to use before it can reach the ID field.由于在您的原始 cpp 文件中,类型Manager未定义,仅声明为,因此编译器无法确定在到达ID字段之前需要使用的内存偏移量。 (A type like this is often called opaque .) Thus the compiler informs you that the type is incomplete. (这样的类型通常称为opaque 。)因此编译器会通知您该类型是不完整的。

The same issue would occur if you attempted to create a variable of type Manager directly, because the compiler does not know how much memory is required to be set aside for this variable.如果您尝试直接创建类型为Manager的变量,则会出现同样的问题,因为编译器不知道需要为该变量留出多少内存。 You could malloc a pointer to Manager , but if you tried to do sizeof(Manager) , it would fail.你可以malloc一个指针Manager ,但如果你试图做sizeof(Manager) ,它会失败。

In order for this to work, the compiler needs to know what the type looks like at the point where you attempt to dereference the pointer.为了使其工作,编译器需要知道在您尝试取消引用指针时的类型是什么样的。 Thus, the struct definition must be placed within the main cpp file, or within any of the headers which are included by that cpp file.因此,结构体定义必须放置在主 cpp 文件中,或者放置在该 cpp 文件包含的任何头文件中。

当我回到家时,我将解决这个问题,这看起来很有趣!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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