Który nagłówek mam dołączyć dla argumentu „size_t”?

98

Według cppreference.com size_t jest zdefiniowany w kilku nagłówkach, a mianowicie

<cstddef>
<cstdio>
<cstring>
<ctime>

A od C ++ 11 również w

<cstdlib>
<cwchar> 

Przede wszystkim zastanawiam się, dlaczego tak jest. Czy nie jest to sprzeczne z zasadą DRY ? Jednak moje pytanie brzmi:

Który z powyższych nagłówków powinienem dołączyć, aby użyć size_t? Czy to w ogóle ma znaczenie?

idclev 463035818
źródło
2
Otwórz odpowiednie pliki nagłówkowe i znajdź definicję.
i486
35
@ i486 - To świetny sposób na pisanie kruchego, nieprzenośnego kodu!
Sean
3
@PanagiotisKanavos C nagłówki, które są częścią standardowej biblioteki C ++ i prawdopodobnie nie są zduplikowane w żadnym z twoich rzekomych nagłówków „prawdziwego C ++”. Co dokładnie miałeś na myśli?
underscore_d
14
I zawsze wykorzystywane <cstddef>dostd::size_t
Boiethios
4
@PanagiotisKanavos Oczywiście, generalnie to dobra rada, ale w tym przypadku nie wydaje się ona trafna - ponieważ nie ma zamiennika dla C ++ std::size_t, a OP nie zalecał używania starszych funkcji C, po prostu obserwując cytat o tym, że dzielą krój pisma. Wątpię, czy ktoś czytający ten wątek zostałby z tego powodu wprowadzony w błąd i użyłby starszych typów / funkcji, ale jeśli chcesz mieć pewność, że tego nie robią, to w porządku!
underscore_d

Odpowiedzi:

94

Zakładając, że chciałem zminimalizować funkcje i typy, które importowałem, wybrałbym, cstddefponieważ nie deklaruje żadnych funkcji i deklaruje tylko 6 typów. Inni koncentrują się na określonych domenach (ciągach znaków, czasie, we / wy), które mogą nie mieć dla Ciebie znaczenia.

Zauważ, że cstddeftylko gwarantuje zdefiniowanie std::size_t, to znaczy definiowanie size_tw przestrzeni nazw std, chociaż może dostarczyć tę nazwę również w globalnej przestrzeni nazw (w rzeczywistości, zwykły size_t).

W przeciwieństwie do tego stddef.h(który jest również nagłówkiem dostępnym w C) gwarantuje zdefiniowanie size_tw globalnej przestrzeni nazw, a także może udostępniać std::size_t.

Sean
źródło
3
Czy jest jakaś gwarancja, że size_tfrom cstddefjest taki sam i zawsze będzie taki sam jak inne? Wygląda na to, że powinien istnieć wspólny plik nagłówkowy z typowymi definicjami, takimi jak size_t...
SnakeDoc
1
@SnakeDoc i jak za dotknięciem czarodziejskiej różdżki, inna odpowiedź tutaj już zauważyła dokładnie to się dzieje, poprzez „wewnętrzny” nagłówek.
underscore_d
5
@SnakeDoc Tak, i to jest nagłówek cstddef.
user253751
2
@SnakeDoc, kto powiedział, że definiują własne? Cały standard mówi, że zostanie zdefiniowany po uwzględnieniu tych nagłówków, nie mówi, że wszyscy muszą go przedefiniować. Wszystkie mogą zawierać <cstddef>lub wszystkie mogą zawierać jakiś wewnętrzny nagłówek, który właśnie definiuje size_t.
Jonathan Wakely
1
Czy csttddefw odpowiedzi jest literówka? Może cstddefma na myśli?
Erik Sjölund
47

W rzeczywistości streszczenie (zawarte w standardzie C ++) kilku nagłówków w szczególności obejmuje, size_ta także dalsze nagłówki definiują typ size_t(w oparciu o standard C, ponieważ <cX>nagłówki to tylko <X.h>nagłówki ISO C ze zauważonymi zmianami, których usunięcie size_tnie jest wskazane).

C średnia ++ jednak odnosi się <cstddef>do zdefiniowaniastd::size_t

  • w 18.2 Typy ,
  • w 5.3.3 Sizeof ,
  • w 3.7.4.2 Funkcje zwalniania przydziałów (co odnosi się do 18.2) i
  • w 3.7.4.1 Funkcje alokacji (odnosi się również do 18.2).

Dlatego i ze względu na fakt, że <cstddef>wprowadza tylko typy, a nie funkcje, trzymałbym się tego nagłówka, aby std::size_tudostępnić.


Zwróć uwagę na kilka rzeczy:

  1. Typ std::size_tmożna uzyskać za pomocą decltypebez nagłówka

    Jeśli planujesz wprowadzić typedef w kodzie i tak (tzn bo piszesz pojemnik i chcą zapewnić size_typetypedef) można korzystać z globalnych sizeof, sizeof...czy alignofoperatorom określić typ bez żadnych nagłówków tym w ogóle od theose operatorzy powrócić std::size_tza standardowej rozdzielczości i możesz decltypena nich użyć :

    using size_type = decltype(alignof(char));
    
  2. std::size_tnie jest per se globalnie widoczny, chociaż funkcje z std::size_targumentami są.

    Niejawnie zadeklarowane globalne funkcje alokacji i zwalniania alokacji

    void* operator new(std::size_t);
    void* operator new[](std::size_t);
    void operator delete(void*);
    void operator delete[](void*);
    

    NIE wprowadzaj size_t, stdani std::size_ti

    odnoszący się do stdlub std::size_tjest nieprawidłowo sformułowany, chyba że nazwa została zadeklarowana przez włączenie odpowiedniego nagłówka.

  3. Użytkownik nie może przedefiniować, std::size_tchociaż możliwe jest posiadanie wielu typów definicji odwołujących się do tego samego typu w tej samej przestrzeni nazw.

    Chociaż występowanie wielu definicji size_twewnątrz stdjest całkowicie poprawne zgodnie z 7.1.3 / 3 , nie jest dozwolone dodawanie żadnych deklaracji namespace stdzgodnie z 17.6.4.2.1 / 1 :

    Zachowanie programu C ++ jest niezdefiniowane, jeśli dodaje on deklaracje lub definicje do standardowej przestrzeni nazw lub do przestrzeni nazw w ramach przestrzeni nazw, chyba że określono inaczej.

    Dodanie właściwej definicji typu for size_tdo przestrzeni nazw nie narusza 7.1.3, ale narusza 17.6.4.2.1 i prowadzi do niezdefiniowanego zachowania.

    Wyjaśnienie: staraj się nie błędnie interpretować 7.1.3 i nie dodawaj deklaracji ani definicji do std(z wyjątkiem kilku przypadków specjalizacji szablonów, w których typedef nie jest specjalizacją szablonu). Rozszerzenienamespace std

Pixelchemist
źródło
1
Tęsknisz za tym, że zduplikowana czcionka nie wprowadza nowego typu. Po prostu dodaje zduplikowany typedef, który jest całkowicie poprawny.
Maxim Egorushkin
@MaximEgorushkin: Nie twierdzę, że dodanie redefinicji typedef do stdjest nieprawidłowe, ponieważ zduplikowane czcionki są nielegalne. Oświadczam, że jest to nielegalne, ponieważ po prostu nie można dodawać do nich definicji namespace std- bez względu na to, czy byłyby one legalne.
Pixelchemist
Co potencjalnie mogłoby się zepsuć, biorąc pod uwagę wszystko, co wiemy ze wszystkich tych standardowych cytatów?
Maxim Egorushkin
12
@MaximEgorushkin: Cokolwiek. Na tym polega niezdefiniowane zachowanie, prawda? Chodzi o to, że może pracować nawet tego stopnia, że nie nie przerwać na dowolnej kompilator nie uzależnia zachowanie programu określonym zgodnie z normą. Lub jako „fredoverflow” umieścić go ładnie tutaj : „C ++ standardowy ma tylko głos, kropka.”
Pixelchemist
Chciałbym, żebyś użył swojego krytycznego myślenia. Co może potencjalnie się zepsuć?
Maxim Egorushkin
9

Wszystkie standardowe pliki nagłówkowe bibliotek mają tę samą definicję; nie ma znaczenia, który z nich umieścisz we własnym kodzie. Na moim komputerze mam następującą deklarację w formacie _stddef.h. Ten plik jest dołączany do każdego wymienionego pliku.

/*
   Define the size_t type in the std namespace if in C++ or globally if in C.
   If we're in C++, make the _SIZE_T macro expand to std::size_t
*/

#if !defined(_SIZE_T) && !defined(_SIZE_T_DEFINED)
#  define _SIZE_T_DEFINED
#if defined(_WIN64)
   typedef unsigned __int64 size_t;
#else
   typedef unsigned int size_t;
#endif
#  if defined(__cplusplus)
#    define _SIZE_T std::size_t
#  else
#    define _SIZE_T size_t
#  endif
#endif
vll
źródło
2
nie jestem pewien, ale myślę, że czas kompilacji ma znaczenie, nie?
idclev 463035818
@ tobi303 nie dotyczy tego konkretnego pytania. Tak, możesz dodać większy nagłówek niż to konieczne, ale wtedy już dodałeś nagłówek C w projekcie C ++. Dlaczego potrzebujesz size_tw pierwszej kolejności?
Panagiotis Kanavos
Nie jest dobrym pomysłem używanie wykrywania makr systemu operacyjnego do definiowania size_t. Możesz zdefiniować to bardziej przenośnie jako using size_t = decltype( sizeof( 42 ) ). Ale nie ma takiej potrzeby, ponieważ <stddef.h>ma prawie zerowy koszt.
Pozdrawiam i hth. - Alf
4

Możesz obejść się bez nagłówka:

using size_t = decltype(sizeof(int));
using size_t = decltype(sizeof 1); //  The shortest is my favourite.
using size_t = decltype(sizeof "anything");

Dzieje się tak, ponieważ standard C ++ wymaga:

Wynikiem sizeofi sizeof...jest stałą typu std::size_t. [Uwaga: std::size_tjest zdefiniowane w standardowym nagłówku <cstddef>(18.2). - notatka końcowa]

Innymi słowy, norma wymaga:

static_assert(std::is_same<decltype(sizeof(int)), std::size_t>::value,
              "This never fails.");

Zauważ również, że jest całkowicie w porządku, aby uczynić tę typedefdeklarację w globalnej i stdprzestrzeni nazw, o ile pasuje ona do wszystkich innych typedefdeklaracji o tej samej nazwie typu (w przypadku niezgodnych deklaracji jest generowany błąd kompilatora).

To dlatego, że:

  • §7.1.3.1 Nazwa typedef-name nie wprowadza nowego typu, tak jak deklaracja klasy (9.1) lub deklaracja wyliczenia.

  • §7.1.3.3 W podanym zakresie nieklasowym typedefspecyfikator może być użyty do przedefiniowania nazwy dowolnego typu zadeklarowanego w tym zakresie w celu odniesienia się do typu, do którego już się odnosi.


Sceptykom, którzy twierdzą, że jest to dodanie nowego typu do przestrzeni nazw std, a takie działanie jest wprost zabronione przez standard, a to jest UB i to wszystko; Muszę powiedzieć, że takie podejście sprowadza się do ignorowania i zaprzeczania głębszemu zrozumieniu podstawowych kwestii.

Standard zabrania dodawania nowych deklaracji i definicji do przestrzeni nazw, stdponieważ w ten sposób użytkownik może narobić bałaganu w bibliotece standardowej i odstrzelić sobie całą nogę. Standardowym autorom łatwiej było pozwolić użytkownikowi wyspecjalizować się w kilku konkretnych rzeczach i zakazać robienia czegokolwiek innego na miarę, zamiast blokować każdą rzecz, której użytkownik nie powinien robić i ryzykować, że przegapi coś ważnego (i tę nogę). Zrobili to w przeszłości, gdy wymagali, aby żaden standardowy kontener nie był tworzony z niekompletnym typem, podczas gdy w rzeczywistości niektóre kontenery mogą to zrobić (zobacz The Standard Librarian: Containers of Incomplete Types, Matthew H. Austern ):

... Ostatecznie wszystko wydawało się zbyt mętne i zbyt słabo zrozumiane; komisja normalizacyjna uważała, że ​​nie ma innego wyboru niż stwierdzenie, że kontenery STL nie powinny działać z niekompletnymi typami. Na wszelki wypadek zastosowaliśmy ten zakaz również do reszty biblioteki standardowej.

... Z perspektywy czasu, teraz, gdy technologia jest lepiej rozumiana, ta decyzja wydaje się zasadniczo słuszna. Tak, w niektórych przypadkach możliwe jest zaimplementowanie niektórych standardowych kontenerów, aby można było tworzyć ich instancje z niekompletnymi typami - ale jest również jasne, że w innych przypadkach byłoby to trudne lub niemożliwe. W większości przypadków był to przypadek, że pierwszy test, który wypróbowaliśmy std::vector, okazał się jednym z łatwych przypadków.

Biorąc pod uwagę, że zasady języka wymagają, std::size_taby być dokładnie decltype(sizeof(int)), robienie namespace std { using size_t = decltype(sizeof(int)); }jest jedną z tych rzeczy, które niczego nie psują.

Przed C ++ 11 nie było, decltypea zatem nie ma możliwości zadeklarowania typu sizeofwyniku w jednej prostej instrukcji bez angażowania dużej liczby szablonów. size_taliasy różnych typów na różnych architekturach docelowych, jednak nie byłoby eleganckim rozwiązaniem dodanie nowego typu wbudowanego tylko dla wyniku działania programu sizeofi nie ma standardowych wbudowanych definicji typów. Stąd najbardziej przenośnym rozwiązaniem w tamtym czasie było umieszczenie size_taliasu typu w jakimś określonym nagłówku i udokumentowanie tego.

W C ++ 11 jest teraz sposób na zapisanie tego dokładnego wymagania standardu jako jednej prostej deklaracji.

Maxim Egorushkin
źródło
6
@Sean To, co napisałeś, nie ma sensu.
Maxim Egorushkin
15
@MaximEgorushkin Połowa z nich nie zrozumiała tego kodu ... działa idealnie. Nie podoba mi się jednak ten sposób: lepiej imo dołączyć nagłówek i pozwolić, aby standard go zdefiniował.
Boiethios
9
Chłopaki, przynajmniej nauczcie się języka efektu, zanim oddacie idealnie poprawne odpowiedzi.
Frédéric Hamidi
11
Tom powiedział: „Istnieje 6 standardowych nagłówków biblioteki definiujących to samo! To szaleństwo! Potrzebujemy jednej i tylko jednej definicji size_t!” Minutę później Mary powiedziała: „OMG! Istnieje 7 definicji size_twszystkich standardowych nagłówków bibliotek i nagłówek projektu, który Tom edytuje! Prawdopodobnie jest ich więcej w bibliotekach innych firm!” xkcd.com/927
6
Chociaż jest to możliwa definicja size_t, nie odpowiada to prawdziwemu pytaniu PO: to tak, jakbym zapytał o nagłówek, w którym FILEjest zadeklarowany, i sugerowałbyś napisanie własnego.
edmz