Почему "typedef struct foo foo;" считается вредным?
В typedef и struct namespaces в C vs С++, один из комментариев, по-видимому, подразумевает, что предоставление некоторого struct foo
предпочтительнее использования typedef вдоль строк...
typedef struct foo foo;
... и затем используя foo
вместо struct foo
во всем API.
Есть ли недостатки в последнем варианте?
Ответы
Ответ 1
Это зависит от того, насколько вам нравится слово struct
. Если вы чувствуете, что ваша программа станет более понятной из-за либерального разбрызгивания struct that
и struct tother
(конечно, у вас не может быть struct this
в C++), тогда непременно используйте версию struct
.
Лично я не думаю, что повторение struct
дает какую-либо выгоду, и я счастлив использовать только имя typedef
. И поскольку C++ эффективно предоставляет объявление typedef struct xyz xyz;
автоматически (оно не совсем точное, не в последнюю очередь потому, что вы можете явно написать это в C++, но оно достаточно близко, чтобы вам, вероятно, не приходилось беспокоиться об этом), Я думаю, что имеет смысл использовать то же самое в C. Компилятор C доволен этим, поэтому я обычно использую typedef struct tag tag;
, а затем использую tag
и tag *
, где это необходимо.
Для альтернативного, но вполне приемлемого представления, прочитайте руководство по стилю кодирования ядра Linux.
Обратите внимание, что C2011 позволяет вам переопределить typedef
, если он имеет псевдоним того же типа:
ISO/IEC 9899: 2011 §6.7 Декларации
Semantics
¶5 Объявление определяет интерпретацию и атрибуты набора идентификаторов. Определение идентификатора - это объявление для этого идентификатора, которое:
- для объекта вызывает сохранение хранилища для этого объекта;
- для функции включает тело функции; 119)
- для константы перечисления является (единственным) объявлением идентификатора;
- для имени typedef - первое (или единственное) объявление идентификатора.
Сравните это с C99, где это было невозможно:
ISO/IEC 9899: 1999 §6.7 Декларации
Semantics
¶5 Объявление определяет интерпретацию и атрибуты набора идентификаторов. Определение идентификатора - это объявление для этого идентификатора, которое:
- для объекта вызывает сохранение хранилища для этого объекта;
- для функции включает тело функции; 98)
- для константы перечисления или имени typedef является (единственным) объявлением Идентификатор.
Это упрощает создание определений типов, если вы последовательны (но только если у вас есть достаточно совместимый компилятор C2011 на каждой платформе, имеющей отношение к вам).
Ответ 2
Единственный недостаток (*) заключается в том, что он скрывает тот факт, что foo
является структурой, а не псевдонимом для некоторого встроенного типа.
Примечание (*): это вопрос вкуса, является ли это недостатком для вас.
- Это полезно для полной непрозрачности (см. первый комментарий ниже).
- Чтобы понять, почему некоторые люди считают это недостатком, проверьте стиль кодирования ядра Linux (глава typedefs).
Ответ 3
О том, есть ли типы структуры typedef:
Вот несколько мнений вокруг (все против структур типефинирования):
Из руководства по стилю OpenBSD:
"Избегайте использования typedef для типов структуры, что делает невозможным использование приложениями указателей на такую структуру, что возможно и полезно при использовании обычного тега структуры".
Из стиля кодирования ядра Linux:
"Ошибочно использовать typedef для структур и указателей".
От Expert C Программирование Питера Ван дер Линдена:
"Не беспокойтесь о typedefs для structs. Все, что они делают, это сохранить ваше слово" struct ", что является ключом, который вы, вероятно, не должны скрывать в любом случае".
Ответ 4
Это более или менее вопрос вкуса.
Просто объявив тег struct
, имя также доступно для переменных, функций или счетчиков в той же области (или даже другого типа, если вам нравится путаница); и пользователи должны написать слово struct
, что делает их код более явным.
Также, объявляя имя типа, вы позволяете людям не набирать struct
, если они не хотят.
Мой комментарий в другом вопросе ссылался на объявление типа указателя с тем же именем, что и тег struct:
typedef struct foo * foo;
Стилистически, это немного неприятно, потому что скрывает тот факт, что это указатель. Это скрывает тот факт, что это указатель; возможно, это хорошо в контексте этого вопроса, где это непрозрачный тип, определенный API, но, на мой взгляд, будет довольно грубым для непрозрачного типа. Он также нарушает совместимость с С++. На этом языке такое объявление недопустимо, поскольку struct foo
вводит foo
в текущее пространство имен, а не в отдельное пространство тегов, и предотвращает объявление любого другого типа с тем же именем в этом пространстве имен.
Ответ 5
Просто придерживайтесь соглашения об именах, и все будет в порядке.
typedef struct
{
//...
} t_mytype;
//...
t_mytype thing;
Таким образом вы узнаете, что это нестандартный тип. Что касается того, что он является структурой, просто используйте явные имена и не реально t_mytype