Quale intestazione dovrei includere per `size_t`?


95

Secondo cppreference.com size_t è definito in diverse intestazioni, vale a dire

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

E, poiché C ++ 11, anche in

<cstdlib>
<cwchar> 

Prima di tutto mi chiedo perché sia ​​così. Non è in contraddizione con il principio DRY ? Tuttavia, la mia domanda è:

Quale delle intestazioni di cui sopra dovrei includere da utilizzare size_t? Ha importanza?


1
Apri i file di intestazione corrispondenti e trova la definizione.
i486

33
@ i486 - È un ottimo modo per scrivere codice fragile non portatile!
Sean

3
@PanagiotisKanavos intestazioni C che fanno parte della libreria standard C ++ e probabilmente non sono duplicate in nessuna delle tue presunte intestazioni "vero C ++". Qual era esattamente il tuo punto?
underscore_d

14
Ho sempre usato <cstddef>perstd::size_t
Boiethios

4
@PanagiotisKanavos Certo, in genere è un buon consiglio, ma in questo caso non sembra rilevante - in quanto non esiste un sostituto C ++ std::size_te l'OP non stava sostenendo l'uso delle funzioni C legacy, ma si limitava a osservare la citazione su di loro che condividono il typedef. Dubito che chiunque legga questo thread sarebbe indotto in errore nell'usare tipi / funzioni legacy per questo motivo, ma se vuoi essere sicuro che non lo facciano, allora abbastanza giusto!
underscore_d

Risposte:


90

Supponendo che volessi ridurre al minimo le funzioni ei tipi che stavo importando, andrei con cstddef perché non dichiara alcuna funzione e dichiara solo 6 tipi. Gli altri si concentrano su domini particolari (stringhe, tempo, IO) che potrebbero non essere importanti per te.

Si noti che cstddefgarantisce solo la definizione std::size_t, ovvero la definizione size_tnello spazio dei nomi std, sebbene possa fornire questo nome anche nello spazio dei nomi globale (in effetti, semplice size_t).

Al contrario, stddef.h(che è anche un'intestazione disponibile in C) garantisce la definizione size_tnello spazio dei nomi globale e può anche fornire std::size_t.


3
C'è qualche garanzia che size_tda cstddefè lo stesso e sarà sempre lo stesso degli altri? Sembra che dovrebbe esserci un file di intestazione comune con definizioni comuni come size_t...
SnakeDoc

1
@SnakeDoc e come per magia, un'altra risposta qui ha già osservato esattamente ciò che accade, tramite un'intestazione "interna".
underscore_d

5
@SnakeDoc Sì, e quell'intestazione è cstddef.
user253751

2
@SnakeDoc, chi dice che definiscono il proprio? Tutto ciò che lo standard dice è che sarà definito dopo aver incluso quelle intestazioni, non dice che tutti devono ridefinirlo. Potrebbero includere tutti <cstddef>o potrebbero includere un'intestazione interna che definisce size_t.
Jonathan Wakely

1
La csttddefrisposta è un errore di battitura? Forse cstddefsi intende?
Erik Sjölund

46

Infatti la sinossi (inclusa nello standard C ++) di diverse intestazioni include specificatamente size_tcosì come ulteriori intestazioni definiscono il tipo size_t(in base allo standard C in quanto le <cX>intestazioni sono solo <X.h>intestazioni ISO C con modifiche annotate dove la rimozione size_tnon è indicata).

Lo standard C ++, tuttavia, fa riferimento <cstddef>per la definizione distd::size_t

  • in 18.2 Tipi ,
  • in 5.3.3 Dimensione di ,
  • in 3.7.4.2 Funzioni di deallocazione (che si riferisce a 18.2) e
  • in 3.7.4.1 Funzioni di allocazione (si rimanda anche a 18.2).

Pertanto, a causa del fatto che <cstddef>introduce solo tipi e nessuna funzione, mi atterrei a questa intestazione per renderla std::size_tdisponibile.


Nota alcune cose:

  1. Il tipo di std::size_tè ottenibile utilizzando decltypesenza includere un'intestazione

    Se avete in programma di introdurre una typedef nel codice in ogni caso (ad esempio perché si scrive un contenitore e si desidera fornire un size_typetypedef) è possibile utilizzare i globali sizeof, sizeof...o alignofgli operatori per definire il tipo senza includere tutte le intestazioni a tutti dato theose operatori restituiscono std::size_tper definizione standard e puoi usare decltypesu di loro:

    using size_type = decltype(alignof(char));
  2. std::size_t non è di per sé visibile a livello globale sebbene funzioni con std::size_t argomenti lo siano.

    Le funzioni di allocazione globale e deallocazione dichiarate implicitamente

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

    NON introdurre size_t,std o std::size_te

    si riferisce stdao std::size_tè mal formato a meno che il nome non sia stato dichiarato includendo l'intestazione appropriata.

  3. L'utente non può ridefinire std::size_t sebbene sia possibile avere più typedef che fanno riferimento allo stesso tipo nello stesso spazio dei nomi.

    Sebbene la ricorrenza di più definizioni di size_tinside stdsia perfettamente valida ai sensi del 7.1.3 / 3 , non è consentito aggiungere dichiarazioni ai namespace stdsensi del 17.6.4.2.1 / 1 :

    Il comportamento di un programma C ++ non è definito se aggiunge dichiarazioni o definizioni allo spazio dei nomi std o a uno spazio dei nomi all'interno dello spazio dei nomi std se non diversamente specificato.

    L'aggiunta di un typedef appropriato per size_tallo spazio dei nomi non viola 7.1.3 ma viola 17.6.4.2.1 e porta a un comportamento indefinito.

    Chiarimento: cerca di non interpretare erroneamente 7.1.3 e non aggiungere dichiarazioni o definizioni a std(tranne alcuni casi di specializzazione del modello in cui un typedef non è una specializzazione del modello). Estendendo ilnamespace std


1
Ti manca il fatto che un typedef duplicato non introduce un nuovo tipo. Aggiunge semplicemente un typedef duplicato, che è perfettamente valido.
Maxim Egorushkin

@ MaximEgorushkin: Non affermo che l'aggiunta di un typedef ridefinito stdnon sia valido perché i typedef duplicati sono illegali. Affermo che è illegale perché semplicemente non puoi aggiungere definizioni a namespace std- non importa se sarebbero legali.
Pixelchemist

Cosa potrebbe potenzialmente rompere, dato tutto ciò che sappiamo da tutte queste citazioni standard?
Maxim Egorushkin

12
@MaximEgorushkin: Anything. Questo è il comportamento indefinito, non è vero? Il punto che può funzionare o anche il punto che non si rompe su alcun compilatore arbitrario non rende il comportamento del programma definito secondo lo standard. O come "fredoverflow" ha detto bene qui : "Lo standard C ++ ha l'unico voto, punto."
Pixelchemist

Vorrei che usassi il tuo pensiero critico. Cosa potrebbe potenzialmente rompersi?
Maxim Egorushkin

9

Tutti i file di intestazione della libreria standard hanno la stessa definizione; non importa quale includi nel tuo codice. Sul mio computer ho la seguente dichiarazione in formato _stddef.h. Questo file è incluso in ogni file elencato.

/*
   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

2
non sono sicuro, ma penso che sia importante per il tempo di compilazione, no?
idclev 463035818

@ tobi303 non per questa domanda specifica. Sì, puoi aggiungere un'intestazione più grande del necessario, ma hai già aggiunto un'intestazione C in un progetto C ++. Perché hai bisogno size_tin primo luogo?
Panagiotis Kanavos

Non è una buona idea usare lo sniffing delle macro del sistema operativo per definire size_t. Puoi definirlo in modo più portabile come using size_t = decltype( sizeof( 42 ) ). Ma non ce n'è bisogno, visto che <stddef.h>ha un costo quasi nullo.
Saluti e salute. - Alf

4

Potresti fare a meno di un'intestazione:

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

Questo perché lo standard C ++ richiede:

Il risultato di sizeofed sizeof...è una costante di tipo std::size_t. [Nota: std::size_tè definito nell'intestazione standard <cstddef>(18.2). - nota finale]

In altre parole, lo standard richiede:

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

Nota anche che va perfettamente bene fare questa typedefdichiarazione nello stdspazio globale e nello spazio dei nomi, purché corrisponda a tutte le altre typedefdichiarazioni dello stesso tipo (viene emesso un errore del compilatore su dichiarazioni non corrispondenti).

Questo è perché:

  • §7.1.3.1 Un typedef-name non introduce un nuovo tipo come fa una dichiarazione di classe (9.1) o una dichiarazione enum.

  • §7.1.3.3 In un dato ambito non di classe, uno typedefspecificatore può essere utilizzato per ridefinire il nome di qualsiasi tipo dichiarato in tale ambito per fare riferimento al tipo a cui si riferisce già.


Agli scettici che dicono che ciò costituisce un'aggiunta di un nuovo tipo nello spazio dei nomi std , e tale atto è esplicitamente proibito dallo standard, e questo è UB e questo è tutto lì; Devo dire che questo atteggiamento equivale a ignorare e negare una comprensione più profonda delle questioni sottostanti.

Lo standard vieta l'aggiunta di nuove dichiarazioni e definizioni nello spazio dei nomi stdperché così facendo l'utente può fare un pasticcio con la libreria standard e sparare a tutta la gamba. Per gli scrittori standard era più facile lasciare che l'utente specializzasse alcune cose specifiche e vietare di fare qualsiasi altra cosa per buona misura, piuttosto che vietare ogni singola cosa che l'utente non dovrebbe fare e rischiare di perdere qualcosa di importante (e quella gamba). Lo hanno fatto in passato quando si richiedeva che nessun contenitore standard fosse istanziato con un tipo incompleto, mentre in realtà alcuni contenitori potevano farlo bene (vedi The Standard Librarian: Containers of Incomplete Types di Matthew H. Austern ):

... Alla fine, sembrava tutto troppo torbido e troppo poco compreso; il comitato di standardizzazione non pensava ci fosse altra scelta se non quella di dire che i contenitori STL non dovrebbero funzionare con tipi incompleti. Per buona misura, abbiamo applicato quel divieto anche al resto della libreria standard.

... In retrospettiva, ora che la tecnologia è meglio compresa, quella decisione sembra ancora fondamentalmente giusta. Sì, in alcuni casi è possibile implementare alcuni dei contenitori standard in modo che possano essere istanziati con tipi incompleti, ma è anche chiaro che in altri casi sarebbe difficile o impossibile. È stato per lo più un caso che il primo test che abbiamo provato, utilizzando std::vector, fosse uno dei casi facili.

Dato che le regole della lingua richiedono std::size_tdi essere esattamente decltype(sizeof(int)), fare namespace std { using size_t = decltype(sizeof(int)); }è una di quelle cose che non infrangono nulla.

Prima di C ++ 11 non c'era decltypee quindi non c'era modo di dichiarare il tipo di sizeofrisultato in una semplice istruzione senza coinvolgere una buona quantità di modelli. size_talias diversi tipi su diverse architetture di destinazione, tuttavia, non sarebbe una soluzione elegante aggiungere un nuovo tipo sizeofpredefinito solo per il risultato di , e non ci sono typedef standard incorporati. Quindi, la soluzione più portabile all'epoca era inserire l' size_talias di tipo in un'intestazione specifica e documentarlo.

In C ++ 11 c'è ora un modo per scrivere quell'esatto requisito dello standard come una semplice dichiarazione.


6
@Sean Quello che hai scritto non ha alcun senso.
Maxim Egorushkin

15
@MaximEgorushkin La metà di loro non ha capito questo codice ... funziona perfettamente. Tuttavia, non mi piace in questo modo: è meglio, imo, includere un'intestazione e lasciare che lo standard lo definisca.
Boiethios

9
Ragazzi, almeno imparate la lingua fottuta prima di votare per risposte perfettamente corrette.
Frédéric Hamidi

11
Tom ha detto: "Ci sono 6 intestazioni di libreria standard che definiscono la stessa cosa! È assurdo! Abbiamo bisogno di una e una sola definizione di size_t!" Un minuto dopo, Mary ha detto: "OMG! Ci sono 7 definizioni di size_tintestazioni di libreria standard e un'intestazione di progetto che Tom sta modificando! Probabilmente ce ne sono di più nelle librerie di terze parti!" xkcd.com/927

6
Sebbene questa sia una possibile definizione di size_t, questa non risponde alla vera domanda dell'OP: è come se chiedessi l'intestazione in cui FILEè dichiarato e tu mi suggerissi di scrivere il mio.
edmz
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.