Widzę zmienne zdefiniowane w tym typie, ale nie wiem, skąd one pochodzą, ani do czego służą. Dlaczego nie użyć int lub unsigned int? (A co z innymi „podobnymi” typami? Void_t itp.).
Widzę zmienne zdefiniowane w tym typie, ale nie wiem, skąd one pochodzą, ani do czego służą. Dlaczego nie użyć int lub unsigned int? (A co z innymi „podobnymi” typami? Void_t itp.).
Odpowiedzi:
stdlib.h
Istddef.h
header pliki określić typ danych o nazwiesize_t
1 , który jest używany do reprezentowania rozmiaru obiektu. Funkcje biblioteczne, które przyjmują rozmiary, oczekują, że będą typusize_t
, a operator sizeof oblicza wartośćsize_t
.Rzeczywisty typ
size_t
zależy od platformy; częstym błędem jest założenie, żesize_t
jest to to samo, co unsigned int, co może prowadzić do błędów w programowaniu, 2 zwłaszcza, gdy coraz bardziej rozpowszechnione są architektury 64-bitowe.
W standardowym nagłówku zdefiniowano następujące typy i makra
stddef.h
<snip>
size_t
który jest typem liczby całkowitej bez znaku wyniku operatora sizeof
int
a unsigned int
typy to 32 bity, a size_t to 64 bity.
Zgodnie z opisem size_t na en.cppreference.com size_t
zdefiniowano w następujących nagłówkach:
std::size_t
...
Defined in header <cstddef>
Defined in header <cstdio>
Defined in header <cstring>
Defined in header <ctime>
Defined in header <cwchar>
size_t
jest typem liczby całkowitej bez znaku wyniku operatora sizeof (ISO C99 sekcja 7.17.)
sizeof
Operator uzyskuje rozmiar (w bajtach) jej argumentu operacji, który może być ekspresja lub nawiasach nazwa typu. Rozmiar jest określany na podstawie typu operandu. Wynik jest liczbą całkowitą. Wartość wyniku jest zdefiniowana w ramach implementacji, a jego typ (typ liczby całkowitej bez znaku) to size_t
(ISO C99 sekcja 6.5.3.4.)
Praktycznie size_t
reprezentuje liczbę bajtów, które możesz zaadresować. W większości nowoczesnych architektur przez ostatnie 10-15 lat było to 32 bity, co również było wielkością niepodpisanego int. Jednak przechodzimy do adresowania 64-bitowego, podczas gdy uint
najprawdopodobniej pozostanie na 32 bitach (jego rozmiar nie jest gwarantowany w standardzie c ++). Aby utworzyć kod, który zależy od rozmiaru pamięci przenośnej między architekturami, należy użyć pliku size_t
. Na przykład rzeczy takie jak rozmiary tablic powinny zawsze używać size_t
's. Jeśli spojrzysz na standardowe kontenery, ::size()
zawsze zwraca a size_t
.
Należy również zauważyć, że program Visual Studio ma opcję kompilacji, która może sprawdzać tego typu błędy o nazwie „Wykryj problemy z 64-bitową mobilnością”.
W ten sposób zawsze wiesz jaki jest rozmiar, ponieważ do rozmiarów dedykowany jest konkretny typ. Samo pytanie pokazuje, że może to być problem: czy to jest int
czy unsigned int
? Ponadto, co jest wielkością ( short
, int
, long
, itd.)?
Ponieważ jest przypisany określony typ, nie musisz martwić się o długość lub liczbę podpisów.
Rzeczywistą definicję można znaleźć w C ++ Reference Library , która mówi:
Typ:
size_t
(typ całkowity bez znaku)Nagłówek:
<cstring>
size_t
odpowiada całkowitemu typowi danych zwróconym przez operator językasizeof
i jest zdefiniowany w<cstring>
pliku nagłówkowym (między innymi) jako typ całkowity bez znaku.W
<cstring>
, jest on stosowany jako typ parametrunum
w funkcjimemchr
,memcmp
,memcpy
,memmove
,memset
,strncat
,strncmp
,strncpy
istrxfrm
, które we wszystkich przypadkach jest używany do określenia maksymalnej liczby bajtów lub znaków funkcja musi mieć wpływ.Jest również stosowany jako typ zwracany do
strcspn
,strlen
,strspn
istrxfrm
do powrotu rozmiarach i długościach.
size_t powinno być zdefiniowane w nagłówkach twojej standardowej biblioteki. Z mojego doświadczenia wynika, że zwykle jest to po prostu typedef do unsigned int. Chodzi jednak o to, że nie musi tak być. Typy, takie jak size_t, pozwalają dostawcy biblioteki standardowej na swobodę zmiany podstawowych typów danych, jeśli jest to odpowiednie dla platformy. Jeśli założysz, że size_t jest zawsze unsigned int (poprzez rzutowanie itp.), Możesz napotkać problemy w przyszłości, jeśli dostawca zmieni size_t na np. Typ 64-bitowy. Z tego powodu zakładanie czegokolwiek na temat tego lub jakiegokolwiek innego typu biblioteki jest niebezpieczne.
Nie jestem zaznajomiony z void_t
wyjątkiem wyniku wyszukiwania Google (nie jest to stosowane w w vmalloc
bibliotece przez Kiem-Phong Vo w AT & T Badań - Jestem pewien, że jest on wykorzystywany w innych bibliotekach, jak również).
Różne typy definicji xxx_t są używane do abstrakcji typu z konkretnej określonej implementacji, ponieważ konkretne typy używane do pewnych rzeczy mogą się różnić w zależności od platformy. Na przykład:
Void_t
wyodrębnia typ wskaźnika zwracanego przez vmalloc
procedury biblioteczne, ponieważ został napisany do pracy w systemach, które są starsze niż ANSI / ISO C, gdzievoid
słowo kluczowe może nie istnieć. Tak przynajmniej przypuszczam.wchar_t
wyodrębnia typ używany dla szerokich znaków, ponieważ w niektórych systemach będzie to typ 16-bitowy, w innych będzie to typ 32-bitowy.Więc jeśli napiszesz swój kod obsługi szerokich znaków, aby użyć wchar_t
typu zamiast, powiedzmy unsigned short
, kod ten będzie prawdopodobnie bardziej przenośny na różne platformy.
W programach minimalistycznych, w których size_t
definicja nie została załadowana „przypadkowo” w niektórych włączeniach, ale nadal potrzebuję jej w pewnym kontekście (na przykład w celu uzyskania dostępu std::vector<double>
), używam tego kontekstu do wyodrębnienia odpowiedniego typu. Na przykład typedef std::vector<double>::size_type size_t
.
(Otocz, namespace {...}
jeśli to konieczne, aby ograniczyć zasięg.)
Jeśli chodzi o „Dlaczego nie używać int lub unsigned int?”, Po prostu dlatego, że jest to semantycznie bardziej sensowne, aby tego nie robić. Istnieje praktyczny powód, dla którego można to, powiedzmy, typedef
d jako an, int
a następnie uaktualnić do long
późniejszego, oczywiście bez konieczności zmiany kodu przez nikogo, ale bardziej fundamentalnie niż to, że typ ma mieć znaczenie. Aby znacznie uprościć, zmienna typu size_t
nadaje się do przechowywania rozmiarów rzeczy i służy do tego, tak jak time_t
nadaje się do przechowywania wartości czasu. Sposób, w jaki są one faktycznie wdrażane, powinien być całkiem właściwy dla implementacji. W porównaniu do zwykłego wywoływania wszystkiego int
, używanie znaczących nazw typów, takich jak ta, pomaga wyjaśnić znaczenie i cel programu, tak jak robi to każdy bogaty zestaw typów.