Какой синтаксически правильный способ объявить структуру C? - PullRequest
31 голосов
/ 15 января 2011

Я видел структуры C, объявленные несколькими различными способами ранее.Почему это так и что, если вообще что-то, каждый делает по-другому?

Например:

struct foo {
  short a;
  int b;
  float c;
};

typedef struct {
  short d;
  int e;
  float f;
} bar;

typedef struct _baz {
  short a;
  int b;
  float c;
} baz;

int main (int argc, char const *argv[])
{
  struct foo a;
  bar b;
  baz c;

  return 0;
}

Ответы [ 4 ]

34 голосов
/ 15 января 2011

Что ж, очевидная разница проявляется в вашем main:

struct foo a;
bar b;
baz c;

Первое объявление имеет формат un- typedef ed struct и требует использования ключевого слова struct.Второй имеет typedef ed анонимный struct, поэтому мы используем имя typedef.Третий сочетает в себе как первое, так и второе: в вашем примере используется baz (что удобно, если коротко), но с тем же эффектом можно использовать struct _baz.

Обновление: ответ larsmans упоминает более распространенный случай, когда вы должны использовать хотя бы struct x { } для создания связанного списка.Второй случай здесь невозможен (если вы не откажетесь от здравомыслия и вместо этого будете использовать void *), поскольку struct является анонимным, а typedef не происходит до тех пор, пока не будет определен struct, что не даст вамспособ сделать (типобезопасный) указатель на сам тип struct.Первая версия отлично подходит для этого использования, но третья, как правило, предпочтительнее по моему опыту.Дайте ему несколько повторений за это.

Более тонкое различие заключается в размещении пространства имен.В C теги struct размещаются в отдельном пространстве имен от других имен, а имена typedef - нет.Таким образом, допустимо следующее:

struct test {
  // contents
};

struct test *test() {
  // contents
}

Но это не так, потому что было бы неоднозначно, как называется test:

typedef struct {
  // contents
} test;

test *test() {
  // contents
}

typedef делает имя короче(всегда плюс), но он помещает его в то же пространство имен, что и ваши переменные и функции.Обычно это не проблема, но это тонкое отличие от простого сокращения.

29 голосов
/ 15 января 2011

Это в основном вопрос личных предпочтений.Мне нравится давать новым типам имя, начинающееся с заглавной буквы, и пропустить struct, поэтому я обычно пишу typedef struct { ... } Foo.Это означает, что я не могу тогда написать struct Foo.

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

typedef struct Node {
    // ...
    struct Node *next;
} Node;

В этом случае вам также необходимо объявитьтип struct Node, поскольку typedef не входит в область действия определения struct.Обратите внимание, что оба имени могут быть одинаковыми (я не уверен, откуда взято соглашение о подчеркивании, но я думаю, что старые компиляторы C не могли обработать typedef struct X X;).

7 голосов
/ 15 января 2011

Все ваши применения синтаксически правильны.Я предпочитаю следующее использование

 /* forward declare all structs and typedefs */
typedef struct foo foo;
.
.
/* declare the struct itself */
struct foo {
  short a;
  int b;
  foo* next;
};

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

5 голосов
/ 12 сентября 2015

Путаница возникает из-за того, что некоторые объявления фактически объявляют до трех конструкций Си.Необходимо помнить о разнице между: 1. объявлением typedef, 2. определением структуры и 3. объявлением структуры.

Все они очень разные конструкции C.Все они делают разные вещи;но вы можете объединить их в одну составную конструкцию, если хотите.

Давайте рассмотрим каждое объявление по очереди.

//================================================
struct foo {
  short a;
  int b;
  float c;
};

Здесь мы используем самый базовый синтаксис определения структуры.Мы определяем foo как тип C , который впоследствии можно будет использовать для объявления переменных этого типа, используя следующий синтаксис:

foo myFoo;  // Declare a struct variable of type foo.

// ========================================================== Это следующее объявление немного похоже напредыдущий синтаксис в том, что он объявляет тип C, но использует синтаксис typedef.Давайте разберем его на компоненты, используя предыдущее базовое объявление.

typedef foo bar; // Declare bar as a variable type, the alias of foo.

bar myBar;       // This is ssemantically the same as: foo myBar;

Теперь просто замените "foo" на предыдущий синтаксис и вуаля!

typedef struct {
  short d;    
  int e;
  float f;
} bar;

//==================================================================
typedef struct _baz {
  short a;
  int b;
  float c;
} baz;

Вышеуказанный синтаксис эквивалентенк следующей последовательности объявлений.

struct _baz {
  short a;
  int b;
  float c;
}

typedef _baz baz; // Declare baz as an alias for _baz.

baz myBaz;       // Is the same as: _baz myBaz;

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