Что представляет собой тип, за которым следует _t (underscore-t)?

261

Это кажется простым вопросом, но я не могу найти его с помощью поиска переполнения стека или Google. Что означает тип, за которым следует _tсреднее? Такие как

int_t anInt;

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

Кевин Гриффин
источник
3
Где int_tопределяется? Если это всегда определено как int, это не полезно; гораздо понятнее использовать intнапрямую. Если это не всегда определяется как int(скажем, если это может быть long intили short int), то это плохо выбранное и запутанное имя.
Кит Томпсон,

Ответы:

213

Как отметил Дуглас Мейл, это в основном обозначает имя типа. Следовательно, вам не рекомендуется заканчивать имена переменных или функций символом ' _t', поскольку это может вызвать некоторую путаницу. А также size_t, стандарт определяет C89 wchar_t, off_t, ptrdiff_t, и , возможно , некоторые другие , которые я забыл. Стандарт C99 определяет множество дополнительных типов, такие как uintptr_t, intmax_t, int8_t, uint_least16_t, uint_fast32_t, и так далее. Эти новые типы формально определены в, <stdint.h>но чаще всего вы будете использовать, <inttypes.h>который (необычно для стандартных заголовков Си) включает <stdint.h>. Он ( <inttypes.h>) также определяет макросы для использования с printf()и scanf().

Как заметил Мэтт Кертис, в суффиксе нет никакого значения для компилятора; это ориентированная на человека конвенция.

Однако следует также отметить, что POSIX определяет множество дополнительных имен типов, заканчивающихся на ' _t', и резервирует суффикс для реализации. Это означает, что если вы работаете в системах, связанных с POSIX, определение собственных имен типов с помощью соглашения не рекомендуется. Система, над которой я работаю, сделала это (более 20 лет); мы регулярно сталкиваемся с системами, определяющими типы с тем же именем, что и мы.

Джонатан Леффлер
источник
4
кажется разумным, что ОС и общие библиотеки времени выполнения определяют типы с обобщенными именами; но не должны ли типы вашей компании также дополняться префиксом или чем-то еще?
Toybuilder
17
Я использую _type вместо _t в моих typedefs именно для того, чтобы избежать этого.
CesarB
4
@Jonathan Leffler - Какое соглашение об именах вы бы использовали для пользовательских типов?
Дж. Эндрю Лафлин
15
@Andrew: если у вас есть удобное сокращение для использования в качестве префикса, тогда вы можете безопасно использовать abbr_xxxxx_tимена типов. Без такого префикса вас могут поймать в любое время. Как правило, стандартизированные _tтипы используют все строчные буквы ( FILEи DIRявляются двумя исключениями, дважды - все заглавные буквы, и нет _t), так что вы можете использовать их CamelCase_tс умеренной безопасностью, с начальными заглавными буквами или без них. Система, над которой я в основном работаю, имеет тенденцию жить опасно и, в _tлюбом случае, использовать ее , но иногда она укусила нас. Я склонен использовать CamelCaseбез суффикса для моей собственной работы; мои функции обычно все в нижнем регистре.
Джонатан Леффлер
5
@JonathanLeffler, я начал использовать это соглашение, CamelCase для типов, нижний регистр для функций. Я искал этот вопрос, надеясь, что я не единственный. Спасибо за подтверждение!
Остин Маллинс
50

Это соглашение используется для именования типов данных, например typedef:


typedef struct {
  char* model;
  int year;
...
} car_t;

mmacaulay
источник
43

_tОбычно оборачивает непрозрачное определение типа.

GCC просто добавляет имена, оканчивающиеся _tна зарезервированное пространство имен, которое вы не можете использовать, чтобы избежать конфликтов с будущими версиями Standard C и POSIX (руководство по библиотеке GNU C) . После некоторых исследований я наконец нашел правильную ссылку в стандарте POSIX (1003.1, Обоснование (информативное)):

B.2.12 Типы данных

Требование, чтобы дополнительные типы, определенные в этом разделе, заканчивались на '' _t '', было вызвано проблемой загрязнения пространства имен. Сложно определить тип (где этот тип не определен IEEE Std 1003.1-2001) в одном заголовочном файле и использовать его в другом без добавления символов в пространство имен программы. Чтобы позволить разработчикам предоставлять свои собственные типы, все соответствующие приложения должны избегать символов, заканчивающихся на «_t», что позволяет разработчику предоставлять дополнительные типы. Поскольку основное использование типов заключается в определении элементов структуры, которые могут (и во многих случаях должны) добавляться к структурам, определенным в стандарте IEEE Std 1003.1-2001, необходимость в дополнительных типах очевидна.

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

Например, ваша программа соответствует POSIX 1003.1 Issues 6, и вы определили тип foo_t. POSIX 1003.1 Проблемы 7 в конечном итоге выпущены с новым определенным типом foo_t. Ваша программа не соответствует новой версии, что может быть проблемой. Ограничение _tиспользования предотвращает рефакторинг кода. Таким образом, если вы стремитесь к соответствию POSIX, вам определенно следует избегать того, _tчто указано в Стандарте.

Примечание: лично я стараюсь придерживаться POSIX, потому что я думаю, что он дает хорошие основы для чистого программирования. Более того, мне очень нравятся рекомендации по стилю кодирования Linux (глава 5) . Есть несколько веских причин, почему не использовать typedef. Надеюсь, это поможет!

Benoit
источник
18

Это стандартное соглашение об именах для типов данных, обычно определяемое с помощью typedefs. Большая часть кода C, который работает с аппаратными регистрами, использует стандартные имена, определенные C99, для типов данных со знаком и без знака фиксированного размера. Как правило, эти имена находятся в стандартном заголовочном файле (stdint.h) и заканчиваются на _t.

mkClark
источник
11

Это просто соглашение, которое означает «тип». Это ничего не значит для компилятора.

Мэтт Кертис
источник
11

По _tсути, не имеет никакого особого значения. Но это стало обычным делом для добавления _tсуффикса к typedef.

Возможно, вы более знакомы с распространенными практиками C для именования переменных ... Это похоже на то, как обычно указатель в начале указателя и использование подчеркивания перед глобальными переменными (это немного реже) и использовать имена переменных i, jи kдля переменных временных циклов.

В коде, где важны размер слова и порядок, очень часто используются явно определенные типы, например BYTE WORD(обычно 16-битные) DWORD(32- битные ).

int_tэто не так хорошо, потому что определение intварьируется между платформами - так, intкому вы соответствуете? (Хотя в наши дни большинство разработок, ориентированных на ПК, рассматривают его как 32-битные, многие вещи для разработки, не относящиеся к ПК, по-прежнему рассматривают int как 16-битные).

Toybuilder
источник
10

Это значит тип. size_tэто тип размера.

Дуглас Мейл
источник
8

Было несколько хороших объяснений по этому вопросу. Просто чтобы добавить еще одну причину для переопределения типов:

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

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

Пример:

typedef unsigned long dc_uint32_t;
Илья
источник
7

Если вы имеете дело с кодом аппаратного интерфейса, автор кода, который вы просматриваете, может быть определен int_tкак целое число определенного размера. Стандарт C не назначает конкретный размер intтипу (возможно, это зависит от вашего компилятора и целевой платформы), и использование определенного int_tтипа позволит избежать этой проблемы переносимости.

Это особенно важно для кода аппаратного интерфейса, поэтому, возможно, вы впервые заметили здесь соглашение.

Грег Хьюгилл
источник
1
это будет не очень хорошая практика, я ожидаю, что один из них определит [u] int_ [32 16 8] _t, чтобы прояснить, какой размер вы определяете.
Илья
1
Вы совершенно правы: «int_t» сам по себе говорит программисту, что это определенный пользователем тип, но не тот, который есть на самом деле!
Грег Хьюгилл
0

Например, в C99 /usr/include/stdint.h:

typedef unsigned char           uint8_t;
typedef unsigned short int      uint16_t;
#ifndef __uint32_t_defined
typedef unsigned int            uint32_t;
# define __uint32_t_defined
#endif
#if __WORDSIZE == 64
typedef unsigned long int       uint64_t;
#else
__extension__
typedef unsigned long long int  uint64_t;
#endif

_t всегда означает определенный typedef.

Jayhello
источник