Указатель на неполный тип класса "struct punto" не допускается

Я пытаюсь создать код, который создает список точек. У меня есть файл с именем «punti.c» с его заголовком и файл с именем «item.c» с его заголовком. Проблема в том, что я не могу получить доступ к переменным точки структуры (x, y) из элемента.

//item.c
#include <stdio.h>
#include "item.h"
#include "punti.h"

int eq(item it1, item it2)
{
    return it1->x == it2->x; //the problem is here
}
//item.h
#include "punti.h"
typedef Punto item;

int eq(item x, item y);
//punti.c
#include "utilities.h"
#include "punti.h"
#include <math.h>

struct punto
{
    double x;
    double y;
};
//punti.h
typedef struct punto *Punto;

Я тестировал тип Punto многими способами, поэтому я уверен, что он работает. Я попытался изменить typedef элемента, сделал его указателем на Punto, но это не сработало. (Часть кода на итальянском, извините :))

вы не можете получить доступ к полям структуры, поскольку они определены в другом файле .c. Структура должна быть определена в заголовочном файле, который вы в настоящее время включаете. Если вы хотите, чтобы это было приватно, переместите код эквалайзера в «punti.c».

Jean-François Fabre 31.03.2023 10:11

Проблема в том, что файл .h говорит только о том, что структура существует. Это не говорит нам, что это за члены. Они видны только внутри punti.c, поэтому их нельзя использовать где-либо еще. Обычное решение состоит в том, чтобы поместить определение структуры также в заголовочный файл.

BoP 31.03.2023 10:13

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

Some programmer dude 31.03.2023 10:13

Пожалуйста, отредактируйте свой вопрос и скопируйте и вставьте команды для компиляции программы и полученную ошибку. C не имеет классов. Пожалуйста, объясните, чего вы хотите достичь, используя разные имена для одного и того же указателя структуры: Punto, item.

Bodo 31.03.2023 10:13

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

Some programmer dude 31.03.2023 10:14

Расширение непрозрачного шрифта (если хотите): punti.h: double getX(struct punto* p); и punto.c: double getX(struct punto* p) { return p->x; }

Aconcagua 31.03.2023 10:17

Дополнительное примечание: пожалуйста, никогда не указывайте typedef — это просто сокрытие информации без каких-либо дополнительных преимуществ (с исключениями просмотра в случаях, когда природа указателя действительно не представляет интереса, например, тип HANDLE в WinAPI). Вместо этого наберите struct: typedef struct punto Punto; и используйте Punto* потом там, где нужен указатель.

Aconcagua 31.03.2023 10:20

Кажется, item это struct punto *, что (не хорошо, но) разрешено. Вы можете иметь указатель на структуру, не зная, что находится внутри структуры. Но как только вы попытаетесь использовать этот «указатель на структуру» для доступа к членам структуры, компилятору необходимо знать, что находится внутри структуры. В вашем случае это не так. Определение структуры находится внутри punti.c, поэтому определение неизвестно при компиляции item.c. Поэтому вы не можете сделать it1->x. Решение: переместите определение в punti.h или переместите функцию eq в punti.c.

Support Ukraine 31.03.2023 10:26

И хорошо подумайте об использовании с плавающей запятой, они имеют довольно много последствий для невозможности точной математики (в основном вокруг проблем округления и сравнений, см., например, здесь , здесь или здесь.

Aconcagua 31.03.2023 10:31

Существуют сценарии, в которых они могут быть значимыми (например, в астрономических приложениях), но в большинстве случаев вам лучше использовать арифметику с фиксированной точкой, т. долларов, мкс вместо мс, ..., при необходимости переключитесь на более крупные типы (uint64_t вместо uint32_t или с помощью какой-либо библиотеки больших целых чисел).

Aconcagua 31.03.2023 10:31

Отвечает ли это на ваш вопрос? разыменование указателя на неполный тип

Karl Knechtel 31.03.2023 11:58

В этом случае я думаю, что причина, по которой несколько человек проголосовали за закрытие вопроса, заключалась в том, что это не был минимально воспроизводимый пример. Вместо того, чтобы публиковать свой код как часть класса Solution, было бы полезнее включить функцию main, которая вызывала бы вашу функцию reverse для определенного ввода, чтобы люди могли видеть, какой ввод вы использовали, какой вывод вы получили и какой вывод вы получили. ожидал.

Stef 04.05.2023 13:05
Стоит ли изучать 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
12
78
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Определение struct punto должно быть известно item.c (например, включено в punti.h).

// punti.h
struct punto
{
    double x;
    double y;
};

typedef struct punto *Punto;

Вы можете думать о typedef как о псевдониме. «Объявление typedef предоставляет способ объявить идентификатор как псевдоним типа, который будет использоваться для замены возможно сложного имени типа» (cppreference). Компилятор просто заменяет typedef тем, что он определяет. Тогда ваша функция эквивалентна:

int eq(struct punto* it1, struct punto* it2)
{
    return it1->x == it2->x;
}

Из-за этого ему нужно знать определение struct punto.


Если вы не хотите, чтобы определение struct punto было известно, вам необходимо предоставить альтернативный способ доступа к его членам. например:

Переполнение стека — что определяет непрозрачный тип в c

//punti.h
typedef struct punto *Punto;
double get_x(Punto p);
//punti.c
...
struct punto
{
    double x;
    double y;
};

double get_x(Punto p)
{
    return p->x;
}
//item.c
...
int eq(item it1, item it2)
{
    // This is ok, as there is no `->` or `*it1`.
    return get_x(it1) == get_x(it2);
}

Спасибо @Someprogrammerdude за идею.

Ответ принят как подходящий

Заголовок punti.h объявляет имя Punto как псевдоним для типа указателя struct punto * на неполный тип struct punto.

//punti.h
typedef struct punto *Punto;

Этот заголовок включен в заголовок item.h, где объявлено имя typedef item как псевдоним для имени typedef Punto, которое используется в списке объявления параметров функции eq:

//item.h
#include "punti.h"
typedef Punto item;

int eq(item x, item y);

Оба имени typedef Punto и item по-прежнему обозначают типы указателей на неполный тип структуры. Их можно использовать в объявлении функции, поскольку сами указатели всегда являются полными типами.

Но тогда в модуле item.c в определении функции eq используются выражения для доступа к элементам данных типа незавершенной структуры struct punto

//item.c
#include <stdio.h>
#include "item.h"
#include "punti.h"

int eq(item it1, item it2)
{
    return it1->x == it2->x; //the problem is here
}

В этот момент компилятор не знает, действительно ли структура struct punto содержит элемент данных x. ТАК выдает ошибку. Вам необходимо включить полное объявление структуры в модули, где есть попытка доступа к элементам данных структуры. В противном случае компилятор сообщит об ошибках.

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

Похожие вопросы

В чем преимущество использования malloc по сравнению с методом объявления массива переменных для использования во время выполнения
Stm32 в качестве ведомого SPI, полнодуплексная передача через циклический буфер DMA: изменения в буфере MISO не (полностью) отражаются при передаче
Проблемы Создание стека с использованием динамической памяти (C)
Проблемы с динамическим выделением памяти (в C)
Является ли SDL_FreeSurface() эквивалентом free() с точки зрения функциональности?
Gcov неправильно обрабатывает комментарии и многострочные предложения
Почему операции peep и pop возвращают мусорное значение?
Munmap_chunk: недопустимый указатель в программе C, использующей функцию в динамической библиотеке, сгенерированной ржавчиной
«поток 1 получил сигнал SIGTRAP, ловушка трассировки/точки останова», что это за ошибка?
Что такое версия C std::byte (для правильной обработки ввода-вывода)