Ich bin verwirrt mit size_t
in C. Ich weiß, dass es von der sizeof
Betreiber. Aber was genau ist er? Ist es ein Datentyp?
Nehmen wir an, ich habe eine for
Schleife:
for(i = 0; i < some_size; i++)
Soll ich die int i;
o size_t i;
?
Ich bin verwirrt mit size_t
in C. Ich weiß, dass es von der sizeof
Betreiber. Aber was genau ist er? Ist es ein Datentyp?
Nehmen wir an, ich habe eine for
Schleife:
for(i = 0; i < some_size; i++)
Soll ich die int i;
o size_t i;
?
Gemäß der ISO C-Norm von 1999 (C99),
size_t
ist eine Ganzzahl ohne Vorzeichen Typ mit mindestens 16 Bit (siehe Abschnitte 7.17 und 7.18.3).
size_t
ist ein Datentyp ohne Vorzeichen der in mehreren C/C++-Standards definiert ist, z.B. der C99 ISO/IEC 9899 Standard, der definiert ist instddef.h
. 1 Sie kann weiter importiert werden durch Einbeziehung vonstdlib.h
da diese Datei intern unter enthältstddef.h
.Dieser Typ wird verwendet, um die Größe eines Objekts. Bibliotheksfunktionen die Größen annehmen oder zurückgeben, erwarten, dass sie vom Typ sein oder den Rückgabetyp von
size_t
. Außerdem ist die am häufigsten am häufigsten verwendete compilerbasierte Operator sizeof auf einen konstanten Wert konstanten Wert auswerten, der kompatibel ist mitsize_t
.
Dies ist eine Konsequenz, size_t
ist ein Typ, der garantiert jeden Array-Index aufnehmen kann.
size_t
ist ein Typ ohne Vorzeichen. Er kann also keine negativen Werte (<0) darstellen. Sie verwenden ihn, wenn Sie etwas zählen und sicher sind, dass es nicht negativ sein kann. Zum Beispiel, strlen()
gibt eine size_t
weil die Länge einer Zeichenkette mindestens 0 sein muss.
Wenn in Ihrem Beispiel der Schleifenindex immer größer als 0 sein wird, könnte es sinnvoll sein, die size_t
oder jeden anderen vorzeichenlosen Datentyp.
Wenn Sie eine size_t
Objekts müssen Sie sicherstellen, dass Sie in allen Kontexten, in denen es verwendet wird, einschließlich der Arithmetik, nicht-negative Werte wünschen. Nehmen wir zum Beispiel an, Sie haben:
size_t s1 = strlen(str1);
size_t s2 = strlen(str2);
und Sie wollen die Differenz der Längen von str2
y str1
. Das können Sie nicht tun:
int diff = s2 - s1; /* bad */
Dies liegt daran, dass der Wert, der dem diff
wird immer eine positive Zahl sein, auch wenn s2 < s1
weil die Berechnung mit vorzeichenlosen Typen durchgeführt wird. In diesem Fall, je nach Anwendungsfall, ist es besser, wenn Sie int
(oder long long
) para s1
y s2
.
Es gibt einige Funktionen in C/POSIX, die Folgendes verwenden könnten/sollten size_t
, aber aus historischen Gründen nicht tun. Zum Beispiel ist der zweite Parameter von fgets
sollte idealerweise sein size_t
sondern ist int
.
Wenn Sie ein empirischer Typ sind ,
echo | gcc -E -xc -include 'stddef.h' - | grep size_t
Ausgabe für Ubuntu 14.04 64-bit GCC 4.8:
typedef long unsigned int size_t;
Beachten Sie, dass stddef.h
wird von GCC und nicht von glibc unter src/gcc/ginclude/stddef.h
im GCC 4.2.
Interessante C99-Auftritte
malloc
nimmt size_t
als Argument und bestimmt damit die maximale Größe, die zugewiesen werden kann.
Und da sie auch von sizeof
Ich denke, dass es die maximale Größe eines Arrays begrenzt.
Siehe auch: Was ist die maximale Größe eines Arrays in C?
Zu den Gründen size_t
zu existieren, und wie wir hierher gekommen sind:
Ganz pragmatisch ausgedrückt, size_t
y ptrdiff_t
sind bei einer 64-Bit-Implementierung garantiert 64 Bit breit, bei einer 32-Bit-Implementierung 32 Bit und so weiter. Sie könnten keinen existierenden Typ dazu zwingen, dies bei jedem Compiler zu bedeuten, ohne Legacy-Code zu zerstören.
A size_t
o ptrdiff_t
ist nicht unbedingt dasselbe wie ein intptr_t
o uintptr_t
. Sie waren auf bestimmten Architekturen, die noch in Gebrauch waren, als size_t
y ptrdiff_t
wurden in den späten 1980er Jahren in die Norm aufgenommen und wurden obsolet, als C99 fügte viele neue Arten, aber noch nicht gegangen (wie 16-Bit-Windows). Der x86 im geschützten 16-Bit-Modus hatte einen segmentierten Speicher, bei dem das größtmögliche Array oder die größte Struktur nur 65.536 Byte groß sein konnte, aber ein far
Der Zeiger musste 32 Bit breit sein, breiter als die Register. Auf diese, intptr_t
wäre 32 Bit breit gewesen, aber size_t
y ptrdiff_t
könnte 16 Bit breit sein und in ein Register passen. Und wer wusste schon, was für ein Betriebssystem in der Zukunft geschrieben werden würde? Theoretisch bietet die i386-Architektur ein 32-Bit-Segmentierungsmodell mit 48-Bit-Zeigern, das jedoch von keinem Betriebssystem jemals tatsächlich verwendet wurde.
Der Typ eines Speicher-Offsets konnte nicht long
denn viel zu viel veralteter Code geht davon aus, dass long
ist genau 32 Bit breit. Diese Annahme wurde sogar in die UNIX- und Windows-APIs eingebaut. Leider ging auch eine Menge anderer Legacy-Code davon aus, dass ein long
ist breit genug, um einen Zeiger, einen Dateiversatz, die Anzahl der seit 1970 verstrichenen Sekunden usw. aufzunehmen. POSIX bietet nun eine standardisierte Möglichkeit, die letztere Annahme anstelle der ersten zu erzwingen, aber keine der beiden Annahmen ist portabel zu machen.
Das kann nicht sein int
weil nur eine kleine Handvoll Compiler in den 90er Jahren die int
64 Bit breit. Dann wurden sie wirklich seltsam und behielten long
32 Bit breit. Die nächste Revision der Norm erklärte es für illegal, wenn int
breiter sein als long
pero int
ist auf den meisten 64-Bit-Systemen immer noch 32 Bit breit.
Das kann nicht sein long long int
die ohnehin erst später hinzugefügt wurde, da sie so angelegt wurde, dass sie auch auf 32-Bit-Systemen mindestens 64 Bit breit ist.
Es wurde also ein neuer Typ benötigt. Selbst wenn dies nicht der Fall wäre, bedeuteten all diese anderen Typen etwas anderes als einen Offset innerhalb eines Arrays oder Objekts. Und wenn es eine Lehre aus dem Fiasko der 32-zu-64-Bit-Migration gab, dann die, dass man sich genau überlegen sollte, welche Eigenschaften ein Typ haben muss, und nicht einen Typ verwenden sollte, der in verschiedenen Programmen etwas anderes bedeutet.
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.