Co oznacza typ, po którym następuje _t ​​(podkreślenie-t)?

261

To wydaje się proste pytanie, ale nie mogę go znaleźć w wyszukiwaniu przepełnienia stosu lub w Google. Co oznacza typ, po którym następuje środek _t? Jak na przykład

int_t anInt;

Widzę to często w kodzie C, który ma ściśle współpracować ze sprzętem - nie mogę nie myśleć, że są ze sobą powiązane.

Kevin Griffin
źródło
3
Gdzie jest int_tzdefiniowane? Jeśli jest zawsze zdefiniowane jako int, nie jest użyteczne; korzystanie z niego jest znacznie łatwiejsze int. Jeśli nie zawsze jest zdefiniowane jako int(powiedzmy, czy może być long intlub short int), to jest to źle wybrana i myląca nazwa.
Keith Thompson,

Odpowiedzi:

213

Jak zauważył Douglas Mayle, w zasadzie oznacza nazwę typu. W związku z tym nie zaleca się kończenia nazw zmiennych lub funkcji znakiem „ _t”, ponieważ może to powodować pewne zamieszanie. Jak również size_ttego, C89 norma określa wchar_t, off_t, ptrdiff_ti prawdopodobnie kilka innych zapomniałem. Średnia C99 określa wiele dodatkowych typów, takich jak uintptr_t, intmax_t, int8_t, uint_least16_t, uint_fast32_t, i tak dalej. Te nowe typy są formalnie zdefiniowane w, <stdint.h>ale najczęściej będziesz ich używać, <inttypes.h>co (wyjątkowo w przypadku standardowych nagłówków C) obejmuje <stdint.h>. ( <inttypes.h>) Definiuje również makra do użytku z printf()i scanf().

Jak zauważył Matt Curtis, kompilator nie ma znaczenia w sufiksie; jest to konwencja zorientowana na człowieka.

Należy jednak pamiętać, że POSIX definiuje wiele dodatkowych nazw typów kończących się na „ _t” i rezerwuje przyrostek do implementacji. Oznacza to, że jeśli pracujesz w systemach związanych z POSIX, nie zaleca się definiowania własnych nazw typów zgodnie z konwencją. System, nad którym pracuję, już to działa (od ponad 20 lat); regularnie jesteśmy zaskoczeni przez systemy definiujące typy o tej samej nazwie, co my.

Jonathan Leffler
źródło
4
wydaje się uzasadnione, że system operacyjny i wspólne biblioteki wykonawcze definiują typy o ogólnych nazwach; ale czy typy Twojej firmy nie powinny być również poprzedzone prefiksem?
Toybuilder
17
Używam _type zamiast _t na moich typedefs właśnie, aby tego uniknąć.
CesarB,
4
@Jathanathan Leffler - Jakiej konwencji nazewnictwa użyłbyś dla typów zdefiniowanych przez użytkownika?
J. Andrew Laughlin,
15
@Andrew: jeśli masz wygodny skrót do użycia jako przedrostek, możesz bezpiecznie używać abbr_xxxxx_tnazw typów. Bez takiego prefiksu możesz zostać złapany w dowolnym momencie. Ogólnie rzecz biorąc, znormalizowane _ttypy używają wszystkich małych liter ( FILEi DIRsą to dwa wyjątki, dwa razy - wszystkie wielkie litery i nie _t), więc możesz używać CamelCase_tz umiarkowanym bezpieczeństwem, z wiodącymi lub bez wielkich liter . System, nad którym głównie pracuję, zwykle żyje niebezpiecznie i używa go _t, ale czasami nas gryzie. Zwykle używam CamelCasebez przyrostka do własnej pracy; moje funkcje są zwykle wszystkie małe.
Jonathan Leffler,
5
@JathanathanLeffler, zacząłem używać tej konwencji, CamelCase dla typów, small_case dla funkcji. Przeszukałem to pytanie, mając nadzieję, że nie tylko ja. Dzięki za walidację!
Austin Mullins,
50

Jest to konwencja używana do nazewnictwa typów danych, np. Z typedef:


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

mmacaulay
źródło
43

_tZazwyczaj owija nieprzezroczystą definicji typu.

GCC po prostu dodaje nazwy kończące się _tdo zarezerwowanej przestrzeni nazw, której nie możesz używać, aby uniknąć konfliktów z przyszłymi wersjami Standard C i POSIX (podręcznik biblioteki GNU C) . Po kilku badaniach w końcu znalazłem prawidłowe odniesienie w standardzie POSIX (1003.1, uzasadnienie (informacyjne)):

B.2.12 Typy danych

Wymaganie, aby dodatkowe typy zdefiniowane w tej sekcji kończyły się na „_t”, wynikało z problemu zanieczyszczenia przestrzeni nazw. Trudno jest zdefiniować typ (gdzie ten typ nie jest zdefiniowany przez IEEE Std 1003.1-2001) w jednym pliku nagłówkowym i użyć go w innym, bez dodawania symboli do przestrzeni nazw programu. Aby umożliwić implementatorom udostępnianie własnych typów, wszystkie zgodne aplikacje są wymagane, aby uniknąć symboli kończących się na „_t”, co pozwala implementatorowi na dostarczenie dodatkowych typów. Ponieważ głównym zastosowaniem typów jest definicja elementów konstrukcyjnych, które można (i w wielu przypadkach trzeba) dodać do struktur zdefiniowanych w IEEE Std 1003.1-2001, potrzeba dodatkowych typów jest przekonująca.

W skrócie, Standard mówi, że istnieją duże szanse na rozszerzenie listy typów Standardów, dlatego Standard ogranicza _tprzestrzeń nazw do własnego użytku.

Na przykład twój program pasuje do POSIX 1003.1 Problem 6 i zdefiniowałeś typ foo_t. POSIX 1003.1 Problem 7 zostaje ostatecznie wydany z nowo zdefiniowanym typem foo_t. Twój program nie pasuje do nowej wersji, co może być problemem. Ograniczenie _tużycia zapobiega refaktoryzacji kodu. Dlatego jeśli dążysz do zgodności z POSIX, zdecydowanie powinieneś unikać tego, _tco określa Standard.

Uwaga dodatkowa: osobiście staram się trzymać POSIX, ponieważ myślę, że daje to dobre podstawy dla czystego programowania. Co więcej, bardzo lubię wytyczne dotyczące Linux Coding Style (rozdział 5) . Istnieje kilka dobrych powodów, dla których nie należy używać typedef. Mam nadzieję, że to pomoże!

Benoit
źródło
18

Jest to standardowa konwencja nazewnictwa dla typów danych, zwykle definiowana przez typedefs. Wiele kodu C, który zajmuje się rejestrami sprzętowymi, używa standardowych nazw zdefiniowanych przez C99 dla podpisanych i niepodpisanych typów danych o stałym rozmiarze. Zgodnie z konwencją nazwy te znajdują się w standardowym pliku nagłówkowym (stdint.h) i kończą się na _t.

mkClark
źródło
11

To tylko konwencja, która oznacza „typ”. Nie oznacza to nic specjalnego dla kompilatora.

Matt Curtis
źródło
11

_tNie z natury mają żadnego specjalnego znaczenia. Ale stało się powszechne, aby dodać _tsufiks do typedef.

Możesz być bardziej zaznajomiony z powszechnymi praktykami C dla nazewnictwa zmiennych ... Jest to podobne do tego, jak często przykleja się ap z przodu wskaźnika i używa znaku podkreślenia przed zmiennymi globalnymi (jest to nieco mniej powszechne) i używać nazw zmiennych i, ji kdla zmiennych tymczasowych pętli.

W kodzie, w którym ważny jest rozmiar słowa i kolejność, bardzo często stosuje się jawnie zdefiniowane typy niestandardowe, takie jak BYTE WORD(zwykle 16-bitowy) DWORD(32-bitowy).

int_tnie jest tak dobra, ponieważ definicja intróżni się w zależności od platformy - więc z intkim się dostosowujesz? (Chociaż w dzisiejszych czasach większość prac rozwojowych zorientowanych na komputery PC traktuje to jako 32 bity, wiele rzeczy do programowania innych niż PC nadal traktuje int jako 16 bitów).

Producent zabawek
źródło
10

Oznacza typ. size_tjest typem rozmiaru.

Douglas Mayle
źródło
8

Było kilka dobrych wyjaśnień na ten temat. Aby dodać kolejny powód do ponownego zdefiniowania typów:

W wielu projektach osadzonych wszystkie typy są redefiniowane w celu poprawnego określenia danego rozmiaru dla typów i w celu poprawy przenośności na różnych platformach (np. Kompilatory typów sprzętu).

Innym powodem będzie uczynienie kodu przenośnym w różnych systemach operacyjnych i uniknięcie kolizji z istniejącymi typami w systemie operacyjnym, które integrujesz z kodem. W tym celu zazwyczaj dodaje się unikalny (jak to możliwe) prefiks.

Przykład:

typedef unsigned long dc_uint32_t;
Ilya
źródło
7

Jeśli masz do czynienia z kodem interfejsu sprzętowego, autor kodu, na który patrzysz, mógł zdefiniować int_tliczbę całkowitą o określonym rozmiarze. Standard C nie przypisuje określonego rozmiaru do inttypu (potencjalnie zależy to od kompilatora i platformy docelowej), a użycie określonego int_ttypu pozwoliłoby uniknąć problemu z przenośnością.

Jest to szczególnie ważne w przypadku kodu interfejsu sprzętowego, dlatego być może po raz pierwszy zauważyłeś tam konwencję.

Greg Hewgill
źródło
1
nie będzie to zbyt dobra praktyka, spodziewam się, że ktoś zdefiniuje [u] int_ [32 16 8] _t, aby wyjaśnić, jaki rozmiar definiujesz.
Ilya
1
Masz całkowitą rację, samo „int_t” informuje programistę, że jest to typ zdefiniowany przez użytkownika, ale nie taki, jaki naprawdę jest!
Greg Hewgill
0

Na przykład w 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 zawsze oznacza zdefiniowane przez typedef.

Jayhello
źródło