C Typedef и Struct Question

Какая разница между этими двумя объявлениями и одна предпочтительна над другой?

typedef struct IOPORT {  
    GPIO_TypeDef* port;  
    u16           pin;  
} IOPORT;  

typedef struct {  
    GPIO_TypeDef* port;  
    u16           pin;  
} IOPORT;  

Ответ 1

Насколько предпочтителен стиль, я предпочитаю 1-й стиль (с именем в теге struct и как typedef для структуры) просто потому, что в исходном файле нет недостатков, кроме нескольких символов. Мой фрагмент структуры IDE отбрасывает имя в обоих местах, поэтому я всегда получаю имя типа typedef, а также имя тэга struct.

Вы получаете несколько небольших преимуществ:

  • "struct STRUCTNAME" может использоваться для объявления указателей на структуру внутри структуры
  • вы можете уйти, просто используя STRUCTNAME в коде C или С++
  • вы предотвращаете потенциальную (даже очень редкую на практике) странность в С++, связанную с именем структуры, используемой для другого объекта без ошибки или предупреждения.

Но если мне удастся вручную ввести определение структуры, я часто лениво пренебрегаю объявлением того или иного имени.

Ответ 2

первый позволяет вам использовать IOPORT внутри структуры для ссылки на объекты того же типа. полезно в таких случаях, как связанные списки, где node должен ссылаться на node.

Ответ 3

C имеет четыре разных пространства имен, где пространство имен тегов структуры является одним из них. Следовательно:

struct foo { int bar; };

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

foo b; /* error */
struct foo b; /* correct */

Кроме того, вы можете создать экземпляр нового объекта сразу в определении следующим образом:

struct foo { int bar; } baz;

Где baz - объект типа структуры foo. Однако часто требуется определить структуру как новый тип, чтобы сохранить некоторые записи. Полный тип не ссылается на теги структуры, поэтому вы можете опустить префикс 'struct' во время объявлений.

typedef struct foo { int bar; } baz;

Все еще позволяет вам объявлять объекты с помощью 'struct foo', поскольку foo является тегом struct. Но теперь он продвигается до полного типа в пространстве имен "нормального" типа, где он известен как тип baz. Таким образом, с помощью typedef поле (-ы) baz имеет другую семантику.

Если вам не нужно объявлять указатели на тип структуры внутри себя (связанные списки, древовидные структуры), опустите его. Добавление того, которое не требуется, просто загрязняет пространство имен.

Ответ 4

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

Ответ 5

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

typedef struct IOPORT_t {  
    GPIO_TypeDef* port;  
    u16           pin;  
} IOPORT; 

.... что подчеркивает разницу между типом и экземпляром.

Кроме того, если вы хотите добавить инициализаторы, вы можете сделать что-то вроде:

typedef struct IOPORT_t {  
    GPIO_TypeDef* port;  
    u16           pin;  
} IOPORT;

struct IOPORT_t IOPORT2 = {
    .port = NULL,
    .pin = 25
  };

или вы можете потерять typedef, чтобы инициализировать его напрямую:

struct IOPORT_t {  
    GPIO_TypeDef* port;  
    u16           pin;  
} IOPORT = {
    .port = NULL,
    .pin = 24
  };

struct IOPORT_t IOPORT2 = {
    .port = NULL,
    .pin = 25
  };