2016-08-07 70 views
2

Wenn size_t nicht definiert ist, heißt es, dass die einzige portable Möglichkeit, die Definition dafür zu erhalten, ist, einen der Header aufzunehmen, die es hat.Betrachtet `size_t` und die Zeigertypen, die sie messen

Allerdings, wie ich es verstehe, ist die Verwendung einer #include in einer Header-Datei schlechte Praxis, weil Header keine anderen Header gehören sollte, nicht wahr?

Es ist also die Aufgabe des Programmierers, einen Weg zu finden, um sicherzustellen, dass ein Header kompiliert wird, ohne in eine schlechte Programmierpraxis zu fallen.

Wie ich es verstehe, ist der size_t Typ der kleinste Typ, der garantiert das längste Objekt unterstützt, das Ihr System verarbeiten kann. Z.B. Wenn Sie ein 64-Bit-Betriebssystem ausführen, sollte size_t 64 Bit sein, denn so arbeiten RAM und Zeiger in und für sich.

Bei Pointern stellt jeder gegebene Pointer einen Offset vom 0. Byte im RAM dar, wobei die Dereferenzierung dieses Offsets den an diesem Offset gespeicherten Wert liefert. Und die CPU (in diesem Fall eine 64-Bit-CPU) hat die volle Verfüg- barkeit, auf die 18-Trillionen-Bytes zuzugreifen, die sie mit der größten Einheit adressieren kann, die sie unterstützt, auch bekannt als 64-Bit-Integer , aka ein Zeiger.

Also, sind nicht size_t und irgendein gegebener Zeigertyp garantiert, um die gleiche Größe zu sein?

Die Frage ist dann, welche der folgenden die beste Praxis für einen bestimmten Header würde:

void some_function(ptr *some_object, size_t n); 
... 

Die Möglichkeiten zu sein scheinen:

#include <stddef.h> 
// would definitely work...but including a header in a header is ugly practice 

typedef long long unsigned size_t 
// to account for win64 making `long` 32-bits...but it's possibly non-portable 

typedef char * size_t 
// I like this one...but am not 100% sure about how portable it is 

Des Weiteren gibt es irgendwelche Gründe Warum wäre die Verwendung eines Zeigers für die Definition von size_t unerwünscht? Es scheint, als ob es in Ordnung sein sollte. Wie ich es verstehe, ist ein Zeiger garantiert die volle Größe eines Registers zu übernehmen und damit die gleiche Größe wie die Architektur sollte die „ideale“ size_t

+7

_Wie ich verstehe, ist die Verwendung eines # include in einer Header-Datei schlechte Übung, weil Header keine anderen Header enthalten sollten, oder? Wo auf der Welt haben Sie diesen Unsinn gehört? Schlag sie für mich, oder? Was Sie in den Headern nicht tun sollten, ist 'using namespace' auf der obersten Ebene (innerhalb von Klassen- und Funktionskörpern ist es jedoch in Ordnung). – Cubic

+0

Btw Ich versuche diese Frage zu schließen, da sie auf einem wirklich großen Missverständnis beruht, aber ich weiß nicht, welcher genaue Grund das wäre. Etwas in der Off-Topic-Kategorie würde ich vermuten? – Cubic

+0

@Cubic Ich denke, ich erinnere mich daran, es in einem Code-Review zu lesen. –

Antwort

7

Wenn size_t ist nicht definiert, es wird gesagt, dass die einzige tragbare Art und Weise die Definition erhalten für eines des Header enthalten ist, die es hat.

Korrekt.

jedoch, wie ich es verstehe, eine #include in einer Header-Datei verwendet, ist schlecht Praxis, weil Header nicht andere Header enthalten sollte, nicht wahr?

Sie wurden falsch informiert. Es gibt keinen Grund, keine Header in andere Header aufzunehmen. Mehrere #include s des gleichen Header können Probleme verursachen wenn sie nicht ordnungsgemäß umfassen umfassen Wächter, aber die Standard-Header sind garantiert zu haben solche Wächter (oder gleichwertig) - und Nicht-Standard-Header sollte haben solche Wachen. (<assert.h> ist ein Sonderfall.)

Wenn Sie size_t benötigen, entweder in einer Quelldatei oder in einer Header-Datei, dann sollten Sie #include <stddef.h> verwenden den Namen size_t sichtbar zu machen (oder Sie können eine der anderen Standard-Header enthalten das macht auch size_t sichtbar).

Einschließlich <stddef.h> in einem Header werden seine Deklarationen in anderen Dateien sichtbar, die Ihre Kopfzeile enthalten, aber das ist kein Problem.

Wie ich es verstehe, die size_t Typ ist der kleinste Typ garantiert die längste Objekt Ihr System verarbeiten kann zu unterstützen.

Es ist ein vorzeichenloser Integertyp, der von der Implementierung zur Speicherung von Größenwerten ausgewählt wurde. Es sollte in der Lage sein, die Größe jedes Objekts in Bytes zu halten (obwohl das nicht explizit garantiert ist). Es gibt keine Garantie, dass es der kleinste solcher Typ ist, und kein Vorteil in der Annahme, dass es ist.

Wie für Zeiger, stellt jede gegebene Zeiger ein von der 0-ten Byte im RAM versetzt, wo dereferenzierenden, dass Sie den Wert an, die gespeichert geben Offset.
[...]
Sind also nicht size_t und irgendein gegebener Zeigertyp garantiert die gleiche Größe?

Nein, es gibt keine solche Garantie. Auf den meisten modernen Systemen stellen Zeiger einen Byte-Offset von virtuelle Adresse 0 dar, aber das ist nicht garantiert. Auf einem System mit einem segmentierten Speichermodell kann die maximale Größe eines einzelnen Objekts viel kleiner sein als die Größe des Speichers. Ein Zeiger kann einen Segmentindikator und einen Byte-Offset enthalten, wobei ein Objekt nicht mehr als ein Segment belegen darf.

Ein Wert vom Typ size_t muss in der Lage sein, die Größe eines einzelnen Objekts darzustellen. Ein Zeiger (zB vom Typ void* oder unsigned char*) muss in der Lage sein, die Adresse irgendeines Objekts oder eines beliebigen Bytes darin darzustellen.

Machen Sie keine unnötigen Annahmen über die Größe von Zeigern oder von size_t. Lassen Sie den Compiler es für Sie herausfinden.

Die Möglichkeiten scheinen zu sein:

#include <stddef.h> 
// would definitely work...but including a header in a header is ugly practice 

Nein, es ist nicht hässlich Praxis. Tun Sie das einfach.

typedef long long unsigned size_t 
// to account for win64 making `long` 32-bits...but it's possibly non-portable 

Dies ist absolut nicht tragbar. Es ist sogar möglich, dass size_t breiter sein könnte als unsigned long long. Aber die Definition Ihres eigenen Typs breiter als der size_t des Compilers ist weder nützlich noch notwendig. Und es wird einen Konflikt erstellen, wenn Sie später einen #include für einen der mehreren Standard-Header hinzufügen, die korrekt definieren size_t (oder für jeden Header, der einen dieser Header enthält).

typedef char * size_t 
// I like this one...but am not 100% sure about how portable it is 

Absolut nicht. size_t muss ein vorzeichenloser Integertyp sein. Wenn Ihnen gesagt wurde, dass Ganzzahlen und Zeiger austauschbar sind, wurden Sie schlecht informiert.

+1

Ausgezeichnete Antwort. Danke, dass Sie alle Missverständnisse ausgeräumt haben und eine gründliche Erklärung gegeben haben. –

1

Wenn Sie size_t benötigen müssen Sie stddef.h wie P. P enthalten sagte in den Kommentaren. Die Definition von size_t in der Norm:

ISO/IEC 9899-2011 sek. 7.19 "Gemeinsame Definitionen"

size_t ist die ganze Zahl ohne Vorzeichen Typ des Ergebnisses der Operator sizeof

Des Weiteren die Größe size_t im Makro

ISO/IEC definiert ist 9.899-2.011 sek. 7.20 SIZE_MAX 65535

(die Zahl 65.535 ist die Mindestgröße)

Also, egal was passiert, müssen Sie stddef.h umfassen.