814 Stimmen

Was ist size_t in C?

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; ?

28voto

codaddict Punkte 426877

Die Manpage für typen.h sagt:

size_t muss eine Ganzzahl ohne Vorzeichen sein

21voto

supercat Punkte 72939

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.

11voto

dtoux Punkte 1624

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).

9voto

Kalana Punkte 5073

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.

Beispiel (mit 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


Beispiel (ohne 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

8voto

l3x Punkte 29224

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:

  • 4K auf einem eingebetteten Gerät
  • 1M unter Win10
  • 7.4M unter Linux

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.com

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.

Powered by:

X