Как я могу скрыть объявление структуры в C?

Один объект, который, кажется, был пропущен, является звездообразными преобразованиями. операторы Index Intersection разрешают предикат путем вычисления набора строк, пораженных каждым из предикатов, прежде чем любой ввод-вывод будет сделан на таблице фактов. На схеме "звезда" Вы индексировали бы каждый отдельный ключ измерения, и оптимизатор запросов может решить который строки выбрать индексным перекрестным вычислением. Индексы на отдельных столбцах дают лучшую гибкость для этого.

10
задан Community 23 May 2017 в 10:29
поделиться

6 ответов

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

В файле public.h :

struct Point;

Point* getSomePoint();

В файле private.h :

struct Point
{
    int x;
    int y;
}

В файле private.c :

Point* getSomePoint()
{
    /* ... */
}

Если вы объединяете эти три файла в библиотеку, вы передаете потребителю библиотеки только public.h и объектный файл библиотеки. .

getSomePoint должен возвращать указатель на Point , потому что public.h не определяет размер Point , только это struct и что она существует.Пользователи библиотеки могут использовать указатели на Point , но не могут получить доступ к элементам или скопировать их, потому что они не знают размер структуры.

Относительно вашего дальнейшего вопроса: Вы не можете разыменовать, потому что программа, использующая библиотеку, имеет только информацию из private.h , которая не содержит объявлений членов. Следовательно, он не может получить доступ к элементам точечной структуры.

Вы можете рассматривать это как функцию инкапсуляции C, точно так же, как вы объявляете члены данных класса C ++ как частные.

30
ответ дан 3 December 2019 в 13:25
поделиться

Он имеет в виду, что вы не можете вернуть структуру по значению в заголовке, потому что для этого структура должна быть полностью объявлена. Но это происходит в файле C (объявление, которое делает X полным типом, «скрыто» в файле C и не отображается в заголовке) в его примере. Следующее объявление объявляет только неполный тип, если это первое объявление структуры

struct X;

Затем вы можете объявить функцию

struct X f(void);

Но вы не можете определить функцию, потому что вы не можете создать переменную этого типа, и тем более вернуть его (размер неизвестен).

struct X f(void) { // <- error here
  // ...
}

Ошибка возникает из-за того, что «x» все еще не заполнен. Теперь, если вы включаете только заголовок с неполным объявлением в нем, вы не можете вызвать эту функцию, потому что выражение вызова функции приведет к неполному типу, что запрещено.

Если бы вы предоставили объявление полного типа struct X между ними, оно было бы действительным

struct X;
struct X f(void);

// ...
struct X { int data; };
struct X f(void) { // valid now: struct X is a complete type
  // ...
}

Это применимо и к способу, использующему typedef : они оба название того же (возможно, неполного) типа. Один раз с использованием обычного идентификатора X , а в другой раз с использованием тега struct X .

и в другой раз с использованием тега struct X .

и в другой раз с использованием тега struct X .

5
ответ дан 3 December 2019 в 13:25
поделиться

Это сообщение означает следующее: если вы видите заголовок

typedef struct _Point Point;

Point * point_new(int x, int y);

, значит, вы не знаете деталей реализации Point .

3
ответ дан 3 December 2019 в 13:25
поделиться

Взгляните на это: непрозрачный указатель

3
ответ дан 3 December 2019 в 13:25
поделиться

В заголовочном файле:

typedef struct _point * Point;

После того, как компилятор увидит это, он знает:

  • есть структура с именем _point
  • есть указатель типа Point, который может ссылаться на _point

Компилятор не знает:

  • как выглядит структура _point
  • какие члены она содержит
  • насколько она велика

И не только компилятор этого не знает - мы, программисты, не знаем » я тоже этого не знаю. Это означает, что мы не можем писать код, который зависит от этих свойств _point, а это означает, что наш код может быть более переносимым.

Используя приведенный выше код, вы можете написать такие функции, как:

Point f() {
   ....
}

, потому что Point - это указатель, а все указатели имеют одинаковый размер, и компилятору не нужно ничего знать о них. Но вы не можете написать функцию, которая возвращает значение по значению:

_point f() {
  ....
}

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

Таким образом, мы можем ссылаться на _point только через тип Point, который на самом деле является указателем. Вот почему в Стандартном C есть такие типы, как FILE, к которым можно получить доступ только через указатель - вы не можете создать экземпляр структуры FILE в своем коде.

5
ответ дан 3 December 2019 в 13:25
поделиться

В качестве альтернативы использованию непрозрачных указателей (как уже упоминалось другими), вы можете вместо этого вернуть непрозрачный пакет байтов, если хотите избежать использования кучи памяти:

// In public.h:
struct Point
{
    uint8_t data[SIZEOF_POINT];  // make sure this size is correct!
};
void MakePoint(struct Point *p);

// In private.h:
struct Point
{
    int x, y, z;
};

void MakePoint(struct Point *p);

// In private.c:
void MakePoint(struct Point *p)
{
    p->x = 1;
    p->y = 2;
    p->z = 3;
}

Затем вы можете создать экземпляры структуры в стеке в клиентском коде, но клиент не знает, что в нем - все, что он знает, это то, что это большой двоичный объект с заданным размером. Конечно, он все еще может получить доступ к данным, если он может угадать смещения и типы данных членов, но опять же, у вас та же проблема с непрозрачными указателями (хотя клиенты не знают размер объекта в этом случае).

Например, различные структуры, используемые в библиотеке pthreads , используют структуры непрозрачных байтов для таких типов, как pthread_t , pthread_cond_t и т. Д. - вы все еще можете создавать экземпляры тех, что находятся в стеке (и вы обычно это делаете), но вы не знаете, что в них находится. Просто загляните в ваш /usr/include/pthreads.h и различные файлы, которые он включает.

1
ответ дан 3 December 2019 в 13:25
поделиться
Другие вопросы по тегам:

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