簡體   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