Что представляет собой тип, за которым следует _t (underscore-t)?
Это кажется простым вопросом, но я не могу найти его с помощью поиска переполнения стека или Google. Что означает тип, сопровождаемый _t
имею в виду? Такие как
int_t anInt;
Я вижу, что многое в коде C предназначено для тесного взаимодействия с оборудованием - я не могу не думать, что они связаны между собой.
10 ответов
Как отметил Дуглас Мейл, это в основном обозначает имя типа. Следовательно, вам не рекомендуется заканчивать имена переменных или функций символом '_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>
который (необычно для стандартных заголовков C) включает в себя <stdint.h>
, Это (<inttypes.h>
) также определяет макросы для использования с printf()
а также scanf()
,
Как заметил Мэтт Кертис, в суффиксе нет никакого значения для компилятора; это ориентированная на человека конвенция.
Однако вы также должны заметить, что POSIX определяет множество дополнительных имен типов, заканчивающихся на '_t
и резервирует суффикс для реализации. Это означает, что если вы работаете в системах, связанных с POSIX, определение собственных имен типов с помощью соглашения не рекомендуется. Система, над которой я работаю, сделала это (более 20 лет); мы регулярно сталкиваемся с системами, определяющими типы с тем же именем, что и мы.
_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, проблемы 6, и вы определили тип foo_t
, POSIX 1003.1 Проблемы 7 в конечном итоге выпущен с новым определенным типом foo_t
, Ваша программа не соответствует новой версии, что может быть проблемой. Ограничение _t
использование препятствует рефакторингу кода. Таким образом, если вы стремитесь к соответствию POSIX, вам определенно следует избегать _t
как говорится в стандарте.
Примечание: лично я стараюсь придерживаться POSIX, потому что я думаю, что он дает хорошие основы для чистого программирования. Более того, мне очень нравятся рекомендации по стилю кодирования Linux (глава 5). Есть несколько веских причин, почему не использовать typedef. Надеюсь, это поможет!
Это соглашение используется для именования типов данных, например, с typedef
:
typedef struct {
char* model;
int year;
...
} car_t;
Это стандартное соглашение об именах для типов данных, обычно определяемое с помощью typedefs. Большая часть кода C, который работает с аппаратными регистрами, использует стандартные имена, определенные C99, для типов данных со знаком и без знака фиксированного размера. Как правило, эти имена находятся в стандартном заголовочном файле (stdint.h) и заканчиваются на _t.
_t
по сути не имеет никакого особого значения. Но это стало обычным делом, чтобы добавить _t
суффикс для typedef.
Возможно, вы более знакомы с распространенными практиками C для именования переменных... Это похоже на то, как обычно для указателя ставится точка "перед" и используется подчеркивание перед глобальными переменными (это немного реже) и использовать имена переменных i
, j
, а также k
для временных переменных цикла.
В коде, где важны размер слова и порядок, очень часто используются явно определенные типы, например: BYTE
WORD
(обычно 16 бит) DWORD
(32 бит).
int_t
не так хорошо, потому что определение int
варьируется между платформами - так чьи int
вы соответствуете? (Хотя в наши дни большинство разработок, ориентированных на ПК, рассматривают его как 32-битные, многие вещи для разработки вне ПК все еще рассматривают int как 16-битные).
Это просто соглашение, которое означает "тип". Это ничего не значит для компилятора.
Было несколько хороших объяснений по этому вопросу. Просто чтобы добавить еще одну причину для переопределения типов:
Во многих встраиваемых проектах все типы переопределяются для правильного определения заданного размера для типов и для улучшения переносимости между различными платформами (например, компиляторами типов оборудования).
Другой причиной будет сделать ваш код переносимым между различными ОС и избежать коллизий с существующими типами в ОС, которые вы интегрируете в свой код. Для этого обычно добавляется уникальный (насколько это возможно) префикс.
Пример:
typedef unsigned long dc_uint32_t;
Если вы имеете дело с кодом аппаратного интерфейса, автор кода, который вы просматриваете, мог бы определить int_t
быть целым числом определенного размера. Стандарт C не назначает определенный размер int
тип (это зависит от вашего компилятора и целевой платформы, потенциально), и с использованием определенного int_t
type избежит этой проблемы переносимости.
Это особенно важно для кода аппаратного интерфейса, поэтому, возможно, вы впервые заметили здесь соглашение.
Например, в 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.