Правильные имена, но "разыменование указателя на неполный тип"

Я застрял с этой ошибкой:

cities.c: In function ‘main’:
cities.c:7:48: error: dereferencing pointer to incomplete type ‘struct Graph’
  printf("well, it got here. nodeCount: %d\n", x->nodeCount);

Все другие решения указывают на то, что имена написаны с ошибками и, следовательно, не определены, однако, если я перенесу определение struct Graph в заголовок, оно будет работать нормально.

Раньше я использовал эту механику в другой моей библиотеке, и она до сих пор отлично компилируется, я потратил часы, пытаясь переместить вещи, но безрезультатно.

график.ч:

#ifndef GRAPH_H
#define GRAPH_H

typedef struct Graph * Graph;

int graphCreate(Graph*, int);
int graphAddPath(Graph, int, int, unsigned int);
int graphRemovePath(Graph, int, int);
int graphDestroy(Graph*);

#endif /* GRAPH_H */

graph.c: https://pastebin.com/FzkaJJwP

города.с:

#include "graph.h"
#include <stdio.h>

int main() {
    Graph x;
    graphCreate(&x, 5);
    printf("well, it got here. nodeCount: %d\n", x->nodeCount);
}

Output is as expected in my library at https://git.mif.vu.lt/emiliskiskis/c_deck.

Спасибо за помощь.

typedef struct Graph * Graph; это вводит в заблуждение, я рекомендую переименовать его во что-то более описательное, например GraphPtr. Потому что люди смотрят на Graph x; и думают, что в стеке есть Graph, хотя на самом деле это просто указатель.
Blaze 28.05.2019 12:10

Вы не можете получить доступ к полям незавершенных структур, struct Graph здесь неполный.

HolyBlackCat 28.05.2019 12:11

Откуда компилятору знать о члене nodeCount, если вы скрываете определение структуры?

Gerhardh 28.05.2019 12:12
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
4
62
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий
  1. Определение struct Graph находится в файле graph.c. Когда вы компилируете файл cities.c, это определение не отображается. Вам нужно переместить определение в graph.h

    struct Graph {
       unsigned int **matrix;
       int nodeCount;
    };
    
  2. Как предложил Блэйз, приведенное ниже определение сбивает с толку. typedef struct Graph * Graph. Лучшим решением было бы

    typedef struct Graph Graph;
    

а затем в коде вы можете использовать

int graphCreate(Graph **, int);
int graphAddPath(Graph *, int, int, unsigned int);
int graphRemovePath(Graph *, int, int);
int graphDestroy(Graph **);

Привет, это была моя личная библиотека (не для совместного использования), поэтому я просто знаю, что происходит, но спасибо за предложение. Я написал функцию для возврата количества узлов, и она работает. Большое спасибо, а также @HolyBlackCat и @Gerhardh!

Emilis Kiškis 28.05.2019 12:20

Сообщение компилятора довольно ясно. Тип является неполным, что в основном означает, что компилятор знает только о существовании структуры с именем Graph, но не знает, как она выглядит. Следствием этого является то, что вы не можете получить доступ к полям.

Итак, сначала вы должны ответить на этот вопрос. Вы хотите, чтобы программист, использующий библиотеку, имел доступ к полям Graph? Если нет, поместите определение в файл .c. Если да, поместите определение в файл .h.

Еще одна вещь, которую следует учитывать, это typedef struct Graph * Graph. Вы скрываете очень много информации при определении типа структуры, и то же самое происходит, когда вы определяете тип указателя. Теперь вы делаете и то, и другое. Мое личное мнение таково, что вам действительно следует избегать этого, если только ответ на приведенный выше вопрос не будет «нет».

Мое предложение: если вы хотите, чтобы пользователь библиотеки мог получить доступ к полям структуры Graph, полностью удалите typedef. Если вы хотите скрыть это от пользователя, используйте функции доступа к коду, например:

// cities.h
int getNodeCount(Graph g);
// cities.c
int getNodeCount(struct Graph * g) {
    return g->nodeCount;
}

И используйте это так:

Graph g;
int nodeCount = getNodeCount(g);

Обратите внимание, что я НЕ использовал typedef в определении функции. Только в своем прототипе.

Спасибо за Ваш ответ. Поскольку я написал эту библиотеку для себя, я просто знаю, как это будет выглядеть, но спасибо за предложения.

Emilis Kiškis 28.05.2019 12:21

Другие вопросы по теме