Зачем использовать разные идентификаторы при структурировании типов? - PullRequest
0 голосов
/ 18 февраля 2019

Рассмотрите этот код:

typedef struct _Node Node;

struct _Node {
    struct _Node * node;
};

или это:

typedef struct _Node {
    struct _Node * node;
} Node;

Есть ли какая-либо причина вообще не переписывать их на

typedef struct Node Node;

struct Node {
    Node * node;
};

и

typedef struct Node {
    Node * node;
} Node;

Насколько я понимаю, они эквивалентны.В чем причина этих префиксов подчеркивания?Я также видел другие варианты, где это не подчеркивание, а заглавная буква в первом вхождении и строчная буква во втором, или что-то еще, что отличает их.Вот один пример:

typedef struct Books {
   char title[50];
   char author[50];
   char subject[100];
   int book_id;
} Book;

Этот пример взят из tutorialspoint , и я знаю, что в целом они не должны рассматриваться как надежный источник.Но есть ли веская причина, чтобы так поступить?

1 Ответ

0 голосов
/ 18 февраля 2019

Люди используют такие имена, как struct _Node, чтобы преднамеренно игнорировать правила, установленные в стандарте (или, чаще, потому что они не знают о правилах, установленных в стандарте).Грубо говоря, в стандарте говорится, что имена, начинающиеся с подчеркивания, в основном зарезервированы для «реализации», то есть компилятора и системных библиотек.См. C11 §7.1.3 Зарезервированные идентификаторы для получения подробной информации:

  • Все идентификаторы, которые начинаются со знака подчеркивания и либо с заглавной буквы, либо другого подчеркивания, всегда зарезервированы для любогоuse.
  • Все идентификаторы, которые начинаются с подчеркивания, всегда зарезервированы для использования в качестве идентификаторов с областью файла как в обычном пространстве, так и в пространстве имен тега.

Также обратите внимание §6.2.1 Области применения идентификаторов - выделение добавлено:

Идентификатор может обозначать объект;функция;тег или член структуры, объединения или перечисления;имя определения типа;название ярлыка;имя макроса;или параметр макроса.Один и тот же идентификатор может обозначать разные объекты в разных точках программы.Член перечисления называется константой перечисления. Имена макросов и параметры макросов здесь далее не рассматриваются, , поскольку до семантической фазы трансляции программ любые вхождения имен макросов в исходном файле заменяются последовательностями токенов предварительной обработки, которые составляют их макроопределения.

Обратите внимание, что POSIX также резервирует суффикс _t - см. Среда компиляции .

Тем не менее, мыслительный процесс выглядит как "это имя не должно"не использовать много; ставьте префикс с подчеркиванием, чтобы не использовать его ".А также «я видел, как это используется в системных заголовках; я скопирую этот стиль», не понимая, что системные заголовки кодируются таким образом, чтобы избежать использования пространства имен, зарезервированного для обычных программистов, и использовать пространство имен, зарезервированное для реализации..

Ваше переписывание разумно;это то, что я обычно делаю.


Чтобы ответить на расширенный вопрос:

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

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

Обратите внимание, что Стандарты кодирования ядра Linux препятствуют использованию typedefs для структурных типов;они требуют, чтобы вы использовали struct WhatEver везде.У правила есть некоторые преимущества и недостатки - самосогласованность, вероятно, важнее, чем соглашение, которое вы используете.Это означает «идти в ногу с потоком» для существующего проекта, но это не имеет большого значения, каким образом вы делаете это в новом проекте, если вы последовательны.

Вы можететакже найдите прецедент для использования альтернативных имен для тегов структуры и соответствующих им имен typedef в священном писании - что означает «язык программирования Си» Кернигана и Ричи.(Интересно, что их примеры несколько изменились между первым изданием 1978 года и вторым изданием 1988 года.)

Второе издание:

typedef struct tnode *Treeptr;

typedef struct tnode {
    …
    Treeptr left;
    Treeptr right;
} Treenode;

Первое издание:

typedef struct tnode {
    …
    struct tnode *left;
    struct tnode *right;
} TREENODE, *TREEPTR;

Обратите внимание, что современный стиль имеет тенденцию избегать использования typedef для указателей.См. Это хорошая идея, чтобы печатать указатели? .

...