Що являє собою тип, за яким слідує _t (підкреслення-t)?


261

Це здається простим запитанням, але я не можу його знайти за допомогою пошуку переповнення стека чи Google. Що означає тип, який супроводжується _tсереднім? Як от

int_t anInt;

Я багато бачу в коді С, який мав на увазі попрацювати з обладнанням - я не можу не вважати, що вони пов'язані.


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>що включає ( як правило, стандартні заголовки C) <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;


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 Випуски 6, і ви визначили тип foo_t. POSIX 1003.1 Випуски 7 , врешті-решт, випускається із заново визначеним типом foo_t. Ваша програма не відповідає новій версії, що може бути проблемою. Обмеження _tвикористання перешкоджає рефакторингу коду. Таким чином, якщо ви прагнете до відповідності POSIX, вам неодмінно слід уникати _tстандартних стандартів.

Побічна примітка: особисто я намагаюся дотримуватися POSIX, тому що я думаю, що це дає хороші основи для чистого програмування. Більше того, мені дуже подобаються вказівки щодо стилю кодування Linux (глава 5) . Є кілька вагомих причин, чому не використовувати typedef. Сподіваюся, що це допоможе!


18

Це стандартна умова іменування для типів даних, як правило, визначених typedefs. Багато коду С, який стосується апаратних регістрів, використовують визначені С99 стандартні імена для підписаних та непідписаних типів даних фіксованого розміру. Зазвичай ці імена містяться у стандартному файлі заголовка (stdint.h) і закінчуються _t.


11

Це просто умова, що означає "тип". Це не означає нічого особливого для компілятора.


11

Це _tне має особливого значення. Але це стало загальним вживанням для додавання _tсуфікса до typedef.

Можливо, ви більше знайомі зі звичайними методами C для іменування змінних ... Це схоже на те, як звичайно вставляти ap на передній панелі для вказівника та використовувати підкреслення перед глобальними змінними (це трохи рідше) і використовувати імена змінних i, jі kдля змінних тимчасових циклів.

У коді, де важливий розмір слів і впорядкування, дуже часто використовувати спеціально визначені типи, які є явними, наприклад BYTE WORD(зазвичай 16-бітний) DWORD(32-бітний).

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



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.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.