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