Как объявить структуру в заголовке, который будет использоваться несколькими файлами в c? - PullRequest
109 голосов
/ 23 октября 2008

Если у меня есть файл source.c со структурой:

struct a { 
    int i;
    struct b {
        int j;
    }
};

Как эту структуру можно использовать в другом файле (т.е. func.c)?

Должен ли я создать новый файл заголовка, объявить там структуру и включить этот заголовок в func.c?

Или я должен определить всю структуру в заголовочном файле и включить ее как в source.c, так и func.c? Как структура может быть объявлена ​​extern в обоих файлах?

Должен ли я typedef это? Если да, то как?

Ответы [ 3 ]

128 голосов
/ 23 октября 2008

если эта структура будет использоваться другим файлом func.c, как это сделать?

Когда тип используется в файле (то есть в файле func.c), он должен быть видимым. Самый худший способ сделать это - скопировать и вставить его в каждый нужный исходный файл.

Правильный способ - поместить его в файл заголовка и включать этот файл заголовка при необходимости.

Должны ли мы открыть новый файл заголовка и объявить там структуру и включить этот заголовок в func.c?

Это решение мне нравится больше, потому что оно делает код очень модульным. Я бы закодировал вашу структуру как:

#ifndef SOME_HEADER_GUARD_WITH_UNIQUE_NAME
#define SOME_HEADER_GUARD_WITH_UNIQUE_NAME

struct a
{ 
    int i;
    struct b
    {
        int j;
    }
};

#endif

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

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

Если вам нужно объявить функцию, используя указатель на структуру, вам не понадобится полное определение структуры. Простая предварительная декларация, такая как:

struct a ;

Будет достаточно, и это уменьшит сцепление.

или мы можем определить общую структуру в заголовочном файле и включить ее как в source.c, так и в func.c?

Это еще один способ, несколько проще, но менее модульный: некоторый код, для работы которого требуется только ваша структура, все равно должен включать все типы.

В C ++ это может привести к интересным усложнениям, но это не по теме (без тега C ++), поэтому я не буду подробно останавливаться.

тогда как объявить эту структуру как extern в обоих файлах.

Возможно, я не вижу смысла, но у Грега Хьюгилла есть очень хороший ответ в его посте Как объявить структуру в заголовке, которая будет использоваться несколькими файлами в c? .

Должны ли мы печатать это тогда как?

  • Если вы используете C ++, не надо.
  • Если вы используете C, вам следует.

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

struct MyStruct ; /* Forward declaration */

struct MyStruct
{
   /* etc. */
} ;

void doSomething(struct MyStruct * p) /* parameter */
{
   struct MyStruct a ; /* variable */
   /* etc */
}

Хотя typedef позволит вам написать его без ключевого слова struct.

struct MyStructTag ; /* Forward declaration */

typedef struct MyStructTag
{
   /* etc. */
} MyStruct ;

void doSomething(MyStruct * p) /* parameter */
{
   MyStruct a ; /* variable */
   /* etc */
}

важно вы все еще сохраняете имя для структуры. Запись:

typedef struct
{
   /* etc. */
} MyStruct ;

просто создаст анонимную структуру с именем typedef-ed, и вы не сможете его предварительно объявить. Поэтому придерживайтесь следующего формата:

typedef struct MyStructTag
{
   /* etc. */
} MyStruct ;

Таким образом, вы сможете использовать MyStruct везде, где хотите избежать добавления ключевого слова struct, и по-прежнему использовать MyStructTag, когда typedef не будет работать (т.е. прямое объявление)

Edit:

Исправлено неверное предположение о объявлении структуры C99, как справедливо заметил Джонатан Леффлер .

Редактировать 2018-06-01:

Крейг Барнс напоминает нам в своем комментарии, что вам не нужно хранить отдельные имена для имени структуры "tag" и его имени "typedef", как я делал выше для ясности.

Действительно, приведенный выше код вполне можно записать так:

typedef struct MyStruct
{
   /* etc. */
} MyStruct ;

IIRC, это именно то, что C ++ делает со своей более простой структурной декларацией, за кулисами, чтобы поддерживать ее совместимость с C:

// C++ explicit declaration by the user
struct MyStruct
{
   /* etc. */
} ;
// C++ standard then implicitly adds the following line
typedef MyStruct MyStruct;

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

31 голосов
/ 23 октября 2008

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

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

extern struct a myAValue;

Затем в одном исходном файле определите фактическую переменную:

struct a myAValue;

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

5 голосов
/ 23 октября 2008

хиджра:

#ifndef A_H
#define A_H

struct a { 
    int i;
    struct b {
        int j;
    }
};

#endif

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...