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;
?
Da es noch niemand erwähnt hat, ist die primäre sprachliche Bedeutung von size_t
ist, dass die sizeof
Operator gibt einen Wert dieses Typs zurück. Ebenso ist die primäre Bedeutung von ptrdiff_t
ist, dass die Subtraktion eines Zeigers von einem anderen einen Wert dieses Typs ergibt. Bibliotheksfunktionen, die dies akzeptieren, tun dies, weil es solchen Funktionen erlaubt, mit Objekten zu arbeiten, deren Größe UINT_MAX auf Systemen überschreitet, auf denen solche Objekte existieren könnten, ohne den Aufrufer zu zwingen, Code zu verschwenden, der einen Wert größer als "unsigned int" auf Systemen übergibt, auf denen der größere Typ für alle möglichen Objekte ausreichen würde.
size_t
y int
sind nicht austauschbar. Zum Beispiel unter 64-Bit-Linux size_t
64 Bit groß ist (d. h. sizeof(void*)
), sondern int
ist 32-Bit.
Beachten Sie auch, dass size_t
ist vorzeichenlos. Wenn Sie eine signierte Version benötigen, gibt es ssize_t
auf einigen Plattformen und wäre für Ihr Beispiel besser geeignet.
Als allgemeine Regel würde ich die Verwendung von int
für die meisten allgemeinen Fälle und verwenden Sie nur size_t
/ ssize_t
wenn ein konkreter Bedarf dafür besteht (mit mmap()
zum Beispiel).
size_t
ist ein vorzeichenloser Integer-Datentyp, der nur 0 und größere als 0 Integer-Werte zuweisen kann. Er misst Bytes der Größe eines beliebigen Objekts und wird zurückgegeben von sizeof
Betreiber.
const
ist die syntaktische Darstellung von size_t
aber ohne const
können Sie das Programm ausführen.
const size_t number;
size_t
regelmäßig für Array-Indizierung und Schleifenzählung verwendet. Wenn der Compiler 32-bit
es würde funktionieren bei unsigned int
. Wenn der Compiler 64-bit
es würde funktionieren bei unsigned long long int
auch. Da für die maximale Größe von size_t
je nach Compilertyp.
size_t
die bereits in der <stdio.h>
Header-Datei, aber sie kann auch durch die <stddef.h>
, <stdlib.h>
, <string.h>
, <time.h>
y <wchar.h>
Kopfzeilen.
const
)#include <stdio.h>
int main()
{
const size_t value = 200;
size_t i;
int arr[value];
for (i = 0 ; i < value ; ++i)
{
arr[i] = i;
}
size_t size = sizeof(arr);
printf("size = %zu\n", size);
}
Ausgabe: size = 800
const
)#include <stdio.h>
int main()
{
size_t value = 200;
size_t i;
int arr[value];
for (i = 0; i < value; ++i)
{
arr[i] = i;
}
size_t size = sizeof(arr);
printf("size = %zu\n", size);
}
Ausgabe: size = 800
size_t
ist ein Typedef, der verwendet wird, um die Größe eines beliebigen Objekts in Bytes darzustellen. (Typedefs werden verwendet, um einen zusätzlichen Namen/Alias für einen anderen Datentyp zu erstellen, aber es wird kein neuer Typ erstellt).
Sie finden es definiert in stddef.h
wie folgt:
typedef unsigned long long size_t;
size_t
ist auch in der <stdio.h>
.
size_t
wird vom sizeof-Operator als Rückgabetyp verwendet.
Utilice size_t
in Verbindung mit sizeof, um den Datentyp des Array-Größenarguments wie folgt zu definieren:
#include <stdio.h>
void disp_ary(int *ary, size_t ary_size)
{
for (int i = 0; i < ary_size; i++)
{
printf("%d ", ary[i]);
}
}
int main(void)
{
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
int ary_size = sizeof(arr)/sizeof(int);
disp_ary(arr, ary_size);
return 0;
}
size_t
ist garantiert groß genug, um die Größe des größten Objekts zu enthalten, das das Hostsystem verarbeiten kann.
Beachten Sie, dass die Größenbeschränkung eines Arrays in Wirklichkeit ein Faktor der Stackgrößenbeschränkung des Systems ist, in dem dieser Code kompiliert und ausgeführt wird. Sie sollten in der Lage sein, die Stackgröße zur Linkzeit anzupassen (siehe ld
Die Befehle stack-size
Parameter).
Um Ihnen eine Vorstellung von den ungefähren Stapelgrößen zu geben:
Viele C-Bibliotheksfunktionen wie malloc
, memcpy
y strlen
deklarieren ihre Argumente und ihren Rückgabetyp als size_t
.
size_t
bietet dem Programmierer die Möglichkeit, mit verschiedenen Typen umzugehen, indem er die Anzahl der benötigten Elemente addiert/subtrahiert, anstatt den Offset in Bytes zu verwenden.
Verschaffen wir uns einen tieferen Einblick in das, was size_t
für uns tun kann, indem wir seine Verwendung in arithmetischen Zeigeroperationen eines C-Strings und eines Integer-Arrays untersuchen:
Hier ist ein Beispiel mit einer C-Zeichenkette:
const char* reverse(char *orig)
{
size_t len = strlen(orig);
char *rev = orig + len - 1;
while (rev >= orig)
{
printf("%c", *rev);
rev = rev - 1; // <= See below
}
return rev;
}
int main() {
char *string = "123";
printf("%c", reverse(string));
}
// Output: 321
0x7ff626939004 "123" // <= orig
0x7ff626939006 "3" // <= rev - 1 of 3
0x7ff626939005 "23" // <= rev - 2 of 3
0x7ff626939004 "123" // <= rev - 3 of 3
0x7ff6aade9003 "" // <= rev is indeterminant. This can be exploited as an out of bounds bug to read memory contents that this program has no business reading.
Das ist nicht sehr hilfreich für das Verständnis der Vorteile der Verwendung von size_t
da ein Zeichen ein Byte ist, unabhängig von Ihrer Architektur.
Wenn wir es mit numerischen Typen zu tun haben, size_t
wird sehr nützlich.
size_t
Typ ist wie eine Ganzzahl mit Vorteilen, die eine physische Speicheradresse enthalten kann; diese Adresse ändert ihre Größe je nach Art der Plattform, auf der sie ausgeführt wird.
Hier sehen Sie, wie wir sizeof und size_t nutzen können, wenn wir ein Array von Ints übergeben:
void print_reverse(int *orig, size_t ary_size)
{
int *rev = orig + ary_size - 1;
while (rev >= orig)
{
printf("%i", *rev);
rev = rev - 1;
}
}
int main()
{
int nums[] = {1, 2, 3};
print_reverse(nums, sizeof(nums)/sizeof(*nums));
return 0;
}
0x617d3ffb44 1 // <= orig
0x617d3ffb4c 3 // <= rev - 1 of 3
0x617d3ffb48 2 // <= rev - 2 of 3
0x617d3ffb44 1 // <= rev - 3 of 3
Oben sehen wir, dass ein int 4 Bytes benötigt (und da es 8 Bits pro Byte gibt, belegt ein int 32 Bits).
Wenn wir ein Array von longs erstellen würden, würden wir feststellen, dass ein long auf einem linux64-Betriebssystem 64 Bit benötigt, aber nur 32 Bits auf einem Win64-System . Daher ist die Verwendung von t_size
spart eine Menge Kodierungsaufwand und potenzielle Fehler, insbesondere bei der Ausführung von C-Code, der Adressarithmetik auf verschiedenen Architekturen durchführt.
Die Moral von der Geschicht ist also: "Benutze size_t
und lassen Sie Ihren C-Compiler die fehleranfällige Arbeit der Zeigerarithmetik erledigen."
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.