Должны ли определения структур идти в .h или .c файл?

Я видел как полные определения struct в заголовках, так и просто объявления - есть ли какое-то преимущество для одного метода над другим?

Если это имеет значение, я обычно набираю структуру, подобную структуре .h

typedef struct s s_t;

Изменить

Чтобы быть ясным, параметры - это объявление в файле заголовка и определении в классе, или как объявление, так и определение в файле заголовка. Оба должны привести к тому же удобству использования, даже если оно связано с привязкой, не так ли?


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

Ответ 1

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

Публичные структуры должны находиться в файле .h.

Ответ 2

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

Нет, если вы не рассматриваете другие .c файлы, включая тот же заголовок. Если определение структуры не отображается компилятору, детали этого определения не могут быть использованы. Объявление без определения (например, просто struct s;) приводит к сбою компилятора, если что-либо пытается заглянуть внутрь struct s, при этом разрешая его, например, compile struct s *foo; (пока foo не будет разыменован).

Сравните эти версии api.h и api.c:

Definition in header:                 Definition in implementation:
+---------------------------------+   +---------------------------------+
| struct s {                      |   | struct s;                       |
|     int internal;               |   |                                 |
|     int other_stuff;            |   | extern void                     |
| };                              |   | api_func(struct s *foo, int x); |
|                                 |   +---------------------------------+
| extern void                     |   +---------------------------------+
| api_func(struct s *foo, int x); |   | #include "api.h"                |
+---------------------------------+   |                                 |
+---------------------------------+   | struct s {                      |
| #include "api.h"                |   |     int internal;               |
|                                 |   |     int other_stuff;            |
| void                            |   | };                              |
| api_func(struct s *foo, int x)  |   |                                 |
| {                               |   | void                            |
|     foo->internal = x;          |   | api_func(struct s *foo, int x)  |
| }                               |   | {                               |
+---------------------------------+   |     foo->internal = x;          |
                                      | }                               |
                                      +---------------------------------+

Этот клиент API работает с любой версией:

#include "api.h"

void good(struct s *foo)
{
    api_func(foo, 123);
}

Этот пример в деталях реализации:

#include "api.h"

void bad(struct s *foo)
{
    foo->internal = 123;
}

который будет работать с версией "определение в заголовке", но не с версией "определение в реализации", так как в последнем случае компилятор не имеет видимости компоновки структуры:

$ gcc -Wall -c bad.c
bad.c: In function 'bad':
bad.c:5: error: dereferencing pointer to incomplete type
$

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

Ответ 3

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

Если структура используется только в одном модуле компиляции (файл .c), вы помещаете его в этот .c файл.

Ответ 4

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

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

Ответ 5

Я помещал их в файл C, чтобы сделать его более объектно-ориентированным, см. эту статью.

Ответ 6

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