Ik word verward met size_t
in C. Ik weet dat het wordt geretourneerd door de sizeof
operator. Maar wat is het precies? Is het een gegevenstype?
Laten we zeggen dat ik een for
lus hebben:
for(i = 0; i < some_size; i++)
Moet ik int i;
of size_t i;
?
Antwoord 1, Autoriteit 100%
Volgens de ISO C-standaard 1999
(C99),size_t
is een niet-ondertekend geheel getal
Type van minimaal 16 bit (zie secties
7.17 en 7.18.3).
size_t
is een niet-ondertekend gegevenstype
gedefinieerd door verschillende C / C++ normen,
b.v. de C9NE ISO / IEC 9899-standaard,
Dat is gedefinieerd instddef.h
. 1 het kan
verder worden geïmporteerd door opname van
stdlib.h
als dit bestand intern sub
Omvatstddef.h
.Dit type wordt gebruikt om de
grootte van een object. Bibliotheekfuncties
die maten innemen of retourneren dat ze ze verwachten
om van het type te zijn of het retourtype te hebben
vansize_t
. Verder het meest
Veelgebruikte compiler-gebaseerd
Operator Maat moet evalueren op een
constante waarde die compatibel is met
size_t
.
Als een implicatie, size_t
is een type gegarandeerd om een array-index vast te houden.
Antwoord 2, Autoriteit 50%
size_t
is een niet-ondertekend type. Dus, het kan geen negatieve waarden (& lt; 0) vertegenwoordigen. Je gebruikt het als je iets telt, en zeker weet dat het niet negatief kan zijn. Bijvoorbeeld, strlen()
retourneert een size_t
Omdat de lengte van een string minimaal 0 moet zijn.
In uw voorbeeld, als uw lus-index altijd groter is dan 0, kan het logisch zijn om size_t
of een ander niet-ondertekend gegevenstype te gebruiken.
Wanneer u een size_t
Object gebruikt, moet u ervoor zorgen dat in alle contexten die het wordt gebruikt, inclusief rekenkunde, u niet-negatieve waarden wilt. Laten we bijvoorbeeld zeggen dat je hebt:
size_t s1 = strlen(str1);
size_t s2 = strlen(str2);
en u wilt het verschil van de lengtes van str2
en str1
vinden. U kunt niet doen:
int diff = s2 - s1; /* bad */
Dit komt omdat de waarde die is toegewezen aan diff
altijd een positief getal zal zijn, zelfs wanneer s2 < s1
, omdat de berekening wordt gedaan met niet-ondertekende typen. In dit geval, afhankelijk van wat uw gebruikscase is, is u misschien beter af met behulp van int
(of long long
) voor s1
en s2
.
Er zijn enkele functies in C / POSIX die / zou kunnen gebruiken size_t
, maar niet vanwege historische redenen. De tweede parameter op fgets
moet bijvoorbeeld idealiter size_t
zijn, maar is int
.
Antwoord 3, Autoriteit 18%
size_t
is een type dat een array-index kan bevatten.
Afhankelijk van de implementatie kan het een van:
zijn
unsigned char
unsigned short
unsigned int
unsigned long
unsigned long long
Hier is hoe size_t
is gedefinieerd in stddef.h
van mijn machine:
typedef unsigned long size_t;
Antwoord 4, Autoriteit 16%
Als u het empirische type bent,
echo | gcc -E -xc -include 'stddef.h' - | grep size_t
Uitvoer voor Ubuntu 14.04 64-bit GCC 4.8:
typedef long unsigned int size_t;
Merk op dat stddef.h
wordt verschaft door GCC en niet GLIBC onder src/gcc/ginclude/stddef.h
IN GCC 4.2.
Interessant C95-optredens
-
malloc
Neemtsize_t
als een argument, dus het bepaalt de maximale grootte die kan worden toegewezen.en aangezien het ook wordt geretourneerd door
sizeof
, denk ik dat het de maximale grootte van elke array beperkt.
Antwoord 5, Autoriteit 5%
De mandpagina voor types.h zegt:
SIFT_T is een niet-ondertekend geheel getal
Antwoord 6, Autoriteit 4%
Omdat nog niemand het heeft genoemd, is de belangrijkste taalkundige betekenis van size_t
dat de operator sizeof
een waarde van dat type retourneert. Evenzo is de primaire betekenis van ptrdiff_t
dat het aftrekken van de ene aanwijzer van de andere een waarde van dat type oplevert. Bibliotheekfuncties die dit accepteren, doen dit omdat dergelijke functies kunnen werken met objecten waarvan de grootte groter is dan UINT_MAX op systemen waar dergelijke objecten zouden kunnen bestaan, zonder dat bellers worden gedwongen code te verspillen die een waarde groter dan “unsigned int” doorgeeft op systemen waar het grotere type zou volstaan voor alle mogelijke objecten.
Antwoord 7, autoriteit 3%
Om in te gaan waarom size_t
moest bestaan en hoe we hier kwamen:
Pragmatisch gezien zijn size_t
en ptrdiff_t
gegarandeerd 64 bits breed bij een 64-bits implementatie, 32 bits breed bij een 32-bits implementatie, enzovoort. Aan. Ze konden geen enkel bestaand type dwingen om dat te betekenen, op elke compiler, zonder de oude code te breken.
Een size_t
of ptrdiff_t
is niet noodzakelijk hetzelfde als een intptr_t
of uintptr_t
. Ze waren anders op bepaalde architecturen die nog in gebruik waren toen size_t
en ptrdiff_t
eind jaren tachtig aan de standaard werden toegevoegd, en verouderd raakten toen C99heeft veel nieuwe typen toegevoegd, maar nog niet verdwenen (zoals 16-bit Windows). De x86 in 16-bits beveiligde modus had een gesegmenteerd geheugen waar de grootst mogelijke array of structuur slechts 65.536 bytes groot kon zijn, maar een far
pointer moest 32 bits breed zijn, breder dan de registers. Daarop zou intptr_t
32 bits breed zijn, maar size_t
en ptrdiff_t
zouden 16 bits breed kunnen zijn en in een register passen. En wie wist wat voor soort besturingssysteem er in de toekomst zou kunnen worden geschreven? In theorie biedt de i386-architectuur een 32-bits segmentatiemodel met 48-bits pointers die geen enkel besturingssysteem ooit heeft gebruikt.
Het type geheugenoffset kan niet long
zijn, omdat veel te veel oude code ervan uitgaat dat long
precies 32 bits breed is. Deze veronderstelling was zelfs ingebouwd in de UNIX- en Windows-API’s. Helaas gingen veel andere oude code er ook van uit dat een long
breed genoeg is om een aanwijzer, een bestandsoffset, het aantal seconden dat is verstreken sinds 1970, enzovoort te bevatten. POSIX biedt nu een gestandaardiseerde manier om de laatste veronderstelling waar te maken in plaats van de eerste, maar geen van beide is een draagbare veronderstelling om te maken.
Het kan niet int
zijn omdat slechts een handvol compilers in de jaren ’90 int
64 bits breed maakten. Toen werden ze echt raar door long
32 bits breed te houden. De volgende herziening van de standaard verklaarde het onwettig voor int
om breder te zijn dan long
, maar int
is nog steeds 32 bits breed op de meeste 64-bits systemen.
Het kan geen long long int
zijn, die sowieso later is toegevoegd, aangezien die is gemaakt om ten minste 64 bits breed te zijn, zelfs op 32-bits systemen.
Er was dus een nieuw type nodig. Zelfs als dat niet zo was, betekenden al die andere typen iets anders dan een offset binnen een array of object. En als er één les was uit het fiasco van 32-naar-64-bits migratie, dan was het om specifiek te zijn over welke eigenschappen een type moest hebben, en niet om er een te gebruiken die verschillende dingen betekende in verschillende programma’s.
Antwoord 8, autoriteit 2%
size_t
en int
zijn niet uitwisselbaar. Op 64-bit Linux is size_t
bijvoorbeeld 64-bit (dwz sizeof(void*)
) maar int
is 32-bit.
Houd er rekening mee dat size_t
niet ondertekend is. Als je een ondertekende versie nodig hebt, dan is er op sommige platforms ssize_t
en dit zou relevanter zijn voor jouw voorbeeld.
Als algemene regel raad ik aan om int
te gebruiken voor de meeste algemene gevallen en alleen size_t
/ssize_t
te gebruiken als er een specifieke behoefte is aan it (met bijvoorbeeld mmap()
).
Antwoord 9, autoriteit 2%
size_t
is een niet-ondertekend geheel getal gegevenstype dat alleen 0 en groter dan 0 gehele getallen kan toewijzen. Het meet bytes van de grootte van elk object en wordt geretourneerd door de operator sizeof
.
const
is de syntaxisweergave van size_t
, maar zonder const
kun je het programma uitvoeren.
const size_t number;
size_t
wordt regelmatig gebruikt voor array-indexering en lustelling. Als de compiler 32-bit
is, zou deze werken op unsigned int
. Als de compiler 64-bit
is, zou deze ook werken op unsigned long long int
. Er is een maximale grootte van size_t
, afhankelijk van het type compiler.
size_t
al gedefinieerd in het <stdio.h>
headerbestand, maar het kan ook worden gedefinieerd door de
<stddef.h>
, <stdlib.h>
, <string.h>
, <time.h>
en <wchar.h>
koppen.
Voorbeeld (met 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);
}
Uitvoer:size = 800
Voorbeeld (zonder 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);
}
Uitvoer:size = 800
Antwoord 10
Als je begint bij 0 en omhoog gaat, gebruik dan in het algemeen altijd een niet-ondertekend type om te voorkomen dat een overflow je in een negatieve waardesituatie brengt. Dit is van cruciaal belang, want als je arraygrenzen kleiner zijn dan het maximum van je lus, maar je lusmaximum is groter dan het maximum van je type, dan zul je negatief worden en kun je een segmentatiefout(SIGSEGV). Gebruik dus in het algemeen nooit int voor een lus die begint bij 0 en omhoog gaat. Gebruik een niet-ondertekend.
Antwoord 11
size_t is een niet-ondertekend geheel getal gegevenstype. Op systemen die de GNU C-bibliotheek gebruiken, is dit unsigned int of unsigned long int. size_t wordt vaak gebruikt voor array-indexering en lustelling.
Antwoord 12
size_tof elk niet-ondertekend type kan worden gebruikt als lusvariabele, aangezien lusvariabelen doorgaans groter dan of gelijk zijn aan 0.
Als we een size_tobject gebruiken, moeten we ervoor zorgen dat we in alle contexten, inclusief rekenkunde, alleen niet-negatieve waarden willen. Het volgende programma zou bijvoorbeeld zeker het onverwachte resultaat geven:
// C program to demonstrate that size_t or
// any unsigned int type should be used
// carefully when used in a loop
#include<stdio.h>
int main()
{
const size_t N = 10;
int a[N];
// This is fine
for (size_t n = 0; n < N; ++n)
a[n] = n;
// But reverse cycles are tricky for unsigned
// types as can lead to infinite loop
for (size_t n = N-1; n >= 0; --n)
printf("%d ", a[n]);
}
Output
Infinite loop and then segmentation fault
Antwoord 13
Dit is een platformspecifieke typedef
. Op een bepaalde computer kan het bijvoorbeeld unsigned int
of unsigned long
zijn. U moet deze definitie gebruiken voor meer draagbaarheid van uw code.
Antwoord 14
Voor zover ik weet, is size_t
een unsigned
integer waarvan de bitgrootte groot genoeg is om een pointer van de oorspronkelijke architectuur te bevatten.
Dus:
sizeof(size_t) >= sizeof(void*)