Как частично объявить структуру, которая определена по типу, во включаемом файле

Я пытаюсь свести к минимуму взаимозависимость файлов #include в качестве общей практики.

В xxx.h у меня есть:

struct my_struct;  // partial decl to satisfy use of my_struct*
void funct(struct my_struct* ms);  // uses the partial def

Как сделать аналогичный частичный decl со структурой typedef? У меня есть фактический decl в каком-то третьем #include, который выглядит (скажем, в yyy.h):

typedef struct my_data_s {
  int ival;
  ... struct's other components ...
} my_data_t;

Мне просто нужен репрезентативный decl в xxx.h, который ссылается на typedef:

typedef struct my_data_s  my_data_t;  // actual full decl is elsewhere
void funct2(my_data_t* md);   

Эта попытка вызывает ошибку «переопределение typedef my_data_t». (Используя gcc 4.4.3/Ubuntu 10.4) Другие попытки случайного поиска (например, добавить '{}' к typedef) также дают ошибки.

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

Я просмотрел другие вопросы и ответы, не смог найти решение этой проблемы. Похоже, должен быть хорошо известный способ сделать это (?!) (Я знаю, что я могу #include yyy.y каждый раз, когда я #include xxx.h - пытаясь избежать таких зависимостей.) Спасибо.


person Art Swri    schedule 15.03.2012    source источник


Ответы (3)


Вы пробовали простой подход:?

ххх.ч

struct my_data_s;
typedef struct my_data_s my_data_t;

гггг.ч

#include "decl.h"
struct my_data_s {
   int foo;
};
person thiton    schedule 15.03.2012
comment
Имеет ту же ошибку, что и моя однострочная версия. Спасибо за идею! - person Art Swri; 15.03.2012
comment
@ArtSwri: Ты действительно не делал того, что он сказал, не так ли? Важная часть состоит в том, чтобы не повторять typedef (именно на это жалуется сообщение об ошибке). - person jamesdlin; 16.03.2012

C99 не позволяет повторять typedef, C11 позволяет.

Просто выполните typedef только один раз и всегда сначала:

typedef struct my_data  my_data;

Также нет необходимости выбирать разные имена для тега struct и идентификатора typedef.

person Jens Gustedt    schedule 15.03.2012
comment
(Я знаю, что вы можете использовать одно и то же имя для struct и typedef, нужно было упомянуть об этом. Мы следуем спецификации кодирования в соответствии с заказом.) Однократное выполнение typedef означает отделение его от struct decl (или я неправильно понимаю?) - person Art Swri; 16.03.2012
comment
@ArtSwri: Почему это имеет значение, если typedef отделено от фактического объявления struct? Это все еще будет рядом с предварительным объявлением. - person jamesdlin; 16.03.2012
comment
@jamesdlin, сам тег struct не нуждается в предварительном объявлении. Из-за ключевого слова struct становится ясно, что речь идет о структуре. Первое размещение typedef отдельно позволяет вам всегда использовать имя typedef без ключевого слова struct, даже внутри фактического объявления struct. - person Jens Gustedt; 16.03.2012
comment
@JensGustedt: Да, я знаю это. Мой комментарий был адресован Арту, у которого были глупые возражения против использования typedef только на месте предварительного объявления. Кого волнует, если это отделено от конкретного определения. - person jamesdlin; 16.03.2012

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

obj_a_defs.h

// contains the definition
// #include'd only by other .h files
...
#define ... // as needed for struct definition
...
typedef struct obj_a {
  ...
} obj_a;

obj_a.h

// contains the 'full info' about obj_a: data and behaviors
// #include'd by other .c files
...
#include "obj_a_defs.h"
...
// declares functions that implement 
// the behaviors associated with obj_a

obj_a.c

...
#include "obj_a.h"
...
// implementations of functions declared in obj_a.h

obj_b.h

// a 'user' of obj_a that uses obj_a as arg
#include "obj_a_defs.h"  // to get the typedef    
...
int some_b_funct(obj_a* obja, ...);
...

obj_b.c

// Defines the 'contract' that this implementation
// is meeting.
#include "obj_b.h"
...
// This .c file includes obj_a.h only if it
// uses the functions defined for obj_a.
// If obj_a is used only to 'pass through'
// to other modules, there's no need for 
// this include.
#include "obj_a.h"  // only if obj_b uses 
...
// obj_b's function implementations

Обоснование/условия

  • typedef и struct хранятся вместе
  • файл .c, который использует obj_X, должен #include "obj_X.h", чтобы показать, что используется
  • избегайте файлов .h, включая другие файлы .h в целом; только файлы 'defs.h' включаются #include в файлы .h.
  • избегайте включения файла #include только для обработки зависимостей; IOW избегайте #include'ing obj_a.h только потому, что он используется в obj_b.h
person Art Swri    schedule 21.03.2012