Объявление структуры в стиле C - PullRequest
8 голосов
/ 25 июля 2011

У меня быстрый вопрос о структурах стиля C. Я копался в некотором примере кода и обнаружил структуру, объявленную следующим образом:

typedef struct _STRUCTNAME
{
   // struct contents
} STRUCTNAME;

Обратите внимание на отсутствие подчеркивания во второй раз, когда появляется STRUCTNAME. Насколько я понимаю, это объявляет одно _STRUCTNAME с именем STRUCTNAME, и больше нельзя создавать объекты этой структуры.

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

const struct STRUCTNAME ARRAYNAME[] = 
{
   // various STRUCTNAMEs declared here
};

Обратите внимание на отсутствие подчеркивания (которое, как мне показалось, было именем экземпляра объекта?)

Мое понимание полностью выключено?

Может кто-нибудь объяснить?

Ответы [ 5 ]

7 голосов
/ 25 июля 2011
typedef struct _STRUCTNAME
{
   // struct contents
} STRUCTNAME;

Этот фрагмент кода выполняет две функции:

  1. Определяет структуру с именем struct _STRUCTNAME и
  2. Создает typedef этой структуры с именем STRUCTNAME.

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

struct _STRUCTNAME structInstance;

Однакос typedef на месте вы можете просто использовать следующее:

STRUCTNAME structInstance;

То же самое относится и к enum объявлениям.

4 голосов
/ 25 июля 2011

STRUCTNAME - это имя определения типа.

_STRUCTNAME - это «тег» для структуры, которая находится в другом пространстве имен.

До стандартизации ANSI структураПространство имен тегов не было отдельным во многих компиляторах, поэтому для предотвращения конфликта имен с именем typedef оно должно быть другим.Однако, поскольку стандартизация не требует, чтобы имя тега было другим.

Вы видите, что эта идиома часто используется в коде Windows, без сомнения, потому что так было во многих примерах из SDK.Некоторое время назад Рэймонд Чен написал в своем блоге сообщение:

Кроме того, я 'Я уверен, что будут некоторые комментарии о том, как идентификатор _STRUCTNAME зарезервирован для реализации, так что в любом случае не стоит использовать эту форму.

2 голосов
/ 25 июля 2011

Майкл Берр сказал:

Также я уверен, что будут некоторые комментарии о том, как идентификатор _STRUCTNAME зарезервирован для реализации, так что это нехорошая идея использовать эту форму в любом случае.

ОК, я игра (но я хотел немного отформатировать, чтобы вы получили ответ вместо этого):

Стандарт языка - этодоговор между автором компилятора и пользователем компилятора, в котором каждый обещает делать, а не делать определенные вещи.

Большинство идентификаторов, начинающихся с _, зарезервированы для реализации, включая все начинающиеся идентификаторыс _, за которым следует заглавная буква.Это означает, что компилятору разрешено использовать их для любых целей, поскольку пользователь компилятора пообещал не использовать их.

Пользователи компиляторов, нарушающие свое обещание, получают странные результаты.

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

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

Я предпочитаю ставить конечные _ на имена тегов, включать в себя охранники и т. д., гарантируя, что я останусь вне пространства реализации;таким образом:

typedef struct STRUCTNAME_
{
   // struct contents
} STRUCTNAME;

(Некоторые пуристы недовольны typedef s просто синтаксическим сахаром, но C тут и там нужно немного сахара, иначе это может показаться довольно мягким.)

0 голосов
/ 25 июля 2011
const struct STRUCTNAME ARRAYNAME[] = 
{
   // various STRUCTNAMEs declared here
};

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

const struct _STRUCTNAME ARRAYNAME[] = ...

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

const STRUCTNAME ARRAYNAME[] =
0 голосов
/ 25 июля 2011

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

Рассмотрите синтаксис для typedef:

typedef type-definition identifier;

. То, что вы сделали, предоставит struct в качествеопределение.Вместо того чтобы создавать экземпляры, вы определяете тип.Сравните это с экземплярами, в которых структура просто определяет тип inline:

struct STRUCTNAME
{
   // struct contents
} myStruct, *ptr, alsoMyStruct;

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

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