it-swarm-tr.com

C size_t nedir?

C'deki size_t ile karıştırılmaya başladım, bunun sizeof operatörü tarafından döndürüldüğünü biliyorum. Ama bu tam olarak nedir? Veri türü mü?

Diyelim ki for döngü var:

for(i = 0; i < some_size; i++)

int i; veya size_t i; kullanmalı mıyım?

528
Vijay

Wikipedia'dan :

1999 ISO C standardına göre. (C99), size_t işaretsiz bir tamsayıdır. en az 16 bit yazın (bkz. bölüm 7.17 ve 7.18.3).

size_t, imzasız bir veri türüdür. birkaç C/C++ standardı ile tanımlanmıştır, Örneğin. C99 ISO/IEC 9899 standardı, bu stddef.h. 1 içinde tanımlanabilir. .__ dahil edilerek daha fazla ithal edilebilir. Bu dosya olarak stdlib.h dahili olarak alt stddef.h içerir.

Bu tip .__ temsil etmek için kullanılır. nesnenin boyutu. Kütüphane fonksiyonları almak veya iade boyutları onları bekliyorlar. türünün olması ya da geri dönüş türünün olması. size_t. Dahası, çoğu. sık kullanılan derleyici tabanlı. işleç sizeof a. ile uyumlu sabit değer. size_t.

Sonuç olarak, size_t, herhangi bir dizi dizinini tutmayı garanti eden bir türdür.

407
sblom

size_t imzasız bir türdür. Bu nedenle, herhangi bir olumsuz değeri temsil edemez (<0). Bir şeyi sayırken kullanırsın ve negatif olamayacağından eminsin. Örneğin, strlen() , bir size_t değerini döndürür, çünkü dizgenin uzunluğu en az 0 olmalıdır.

Örneğinizde, döngü endeksiniz her zaman 0'dan büyük olacaksa, size_t veya başka bir imzasız veri türünü kullanmak anlamlı olabilir.

Bir size_t nesnesi kullandığınızda, kullanıldığı tüm bağlamlarda, aritmetik de dahil olmak üzere negatif olmayan değerler istediğinizden emin olmalısınız. Örneğin, diyelim ki:

size_t s1 = strlen(str1);
size_t s2 = strlen(str2);

ve str2 ve str1 uzunluklarının farkını bulmak istiyorsunuz. Yapamazsın:

int diff = s2 - s1; /* bad */

Bunun nedeni, diff öğesine atanan değerin s2 < s1 olsa bile her zaman pozitif bir sayı olacağından, hesaplama imzasız türlerle yapıldığındandır. Bu durumda, kullanım durumunuzun ne olduğuna bağlı olarak, long long ve s1 için int (veya s2) kullanarak daha iyi olabilirsiniz.

C/POSIX'de size_t kullanabilecek/kullanması gereken bazı işlevler vardır, ancak geçmiş nedenlerden ötürü kullanmazlar. Örneğin, fgets öğesinin ikinci parametresi ideal olarak size_t olmalıdır, ancak int.

195
Alok Singhal

size_t, herhangi bir dizi dizinini tutabilen bir türdür.

Uygulamaya bağlı olarak, aşağıdakilerden herhangi biri olabilir:

unsigned char

unsigned short

unsigned int

unsigned long

unsigned long long

Makinemin size_t dosyasında stddef.h nasıl tanımlanır:

typedef unsigned long size_t;
64
Arjun Sreedharan

Eğer ampirik bir türsünüz,

echo | gcc -E -xc -include 'stddef.h' - | grep size_t

Ubuntu 14.04 64-bit GCC 4.8 için çıktı:

typedef long unsigned int size_t;

stddef.h'nun GCC tarafından sağlandığını ve GCC 4.2'de src/gcc/ginclude/stddef.h altında glibc'nin sağlanmadığını unutmayın.

İlginç C99 görünümleri

  • malloc, size_t işlevini bir argüman olarak alır, bu nedenle atanabilecek maksimum boyutu belirler.

    Ayrıca sizeof tarafından döndürüldüğünden, herhangi bir dizinin maksimum boyutunu sınırladığını düşünüyorum.

    Ayrıca bakınız: C'deki bir dizinin maksimum boyutu nedir?

types.h adlı kullanıcı sayfası:

size_t işaretsiz bir tamsayı türü olmalıdır

18
codaddict

Kimse henüz bahsetmediğinden, size_t dilinin asıl önemi sizeof işlecinin bu tür bir değer vermesidir. Aynı şekilde, ptrdiff_t 'nin birincil önemi, bir göstericiyi diğerinden çıkarmanın, bu tür bir değer vermesidir. Bunu kabul eden kütüphane işlevleri, bu tür işlevlerin, arayanların daha büyük tipteki sistemlerde "imzasız int" den daha büyük bir değerden geçen bir kodu boşa harcamasına zorlamadan, bu tür nesnelerin olabileceği sistemlerde boyutu UINT_MAX'ı aşan nesnelerle çalışmasına izin vereceği için yapar olası tüm nesneler için yeterli olacaktır.

13
supercat

size_t ve int değiştirilemez. Örneğin 64-bit Linux'ta size_t 64-bit boyutunda (yani sizeof(void*)), ancak int 32-bit'dir.

Ayrıca, size_t dosyasının imzasız olduğuna dikkat edin. İmzalı bir sürüme ihtiyacınız varsa, o zaman bazı platformlarda ssize_t vardır ve bu sizin örneğinizle daha alakalı olacaktır.

Genel bir kural olarak, çoğu genel durum için int kullanılmasını öneririm ve yalnızca belirli bir ihtiyaç olduğunda (örneğin mmap() ile) size_t/ssize_t kullanın.

5
dtoux

Neden size_t'un olması gerektiğine ve buraya nasıl geldiğimize karar vermek için:

Pratik açıdan, size_t ve ptrdiff_t adreslerinin 64 bit uygulamada 64 bit, 32 bit uygulamada 32 bit vb. Olduğu garantilidir. Var olan herhangi bir türü, her derleyicide eski kodları bozmadan kastetmeye zorlayamazlardı.

Bir size_t veya ptrdiff_t, mutlaka bir intptr_t veya uintptr_t ile aynı değildir. 80'lerin sonunda size_t ve ptrdiff_t Standarda eklendiğinde ve C99 birçok yeni tür eklediğinde (henüz 16 bit Windows gibi) kullanılmadığında eski hale geldiklerinde hala kullanılan bazı mimarilerde farklıydı. 16 bitlik korumalı moddaki x86, mümkün olan en büyük dizinin veya yapının yalnızca 65,536 bayt boyutunda olabileceği, ancak bir far göstergesinin kayıtlardan daha geniş 32 bit olması gereken bölümlenmiş bir belleğe sahiptir. Bunlarda, intptr_t 32 bit genişliğinde olabilirdi, ancak size_t ve ptrdiff_t 16 bit genişliğinde olabilir ve bir sicile sığabilir. Gelecekte ne tür bir işletim sisteminin yazılabileceğini kim bilebilirdi? Teoride, i386 mimarisi, hiçbir işletim sisteminin gerçekte kullanmadığı 48 bit işaretçilerle 32 bit segmentasyon modeli sunar.

Bir bellek kayması türü long olamaz, çünkü çok fazla eski kod long öğesinin tam olarak 32 bit genişliğinde olduğunu varsayar. Bu varsayım, UNIX ve Windows API'lerinde bile yapıldı. Ne yazık ki, pek çok başka eski kod da long öğesinin bir işaretçiyi, dosya ofsetini, 1970'ten beri geçen saniye sayısını vb. Tutacak kadar geniş olduğunu varsaymıştır. POSIX şimdi bu ikinci varsayımı eskinin yerine doğru olmaya zorlamak için standart bir yol sağlar, ancak hiçbiri de taşınabilir bir varsayım değildir.

int olamazdı çünkü 90'larda sadece küçük bir avuç derleyici int 64 bit genişliğinde yaptı. Sonra long 32 bit genişliğinde tutarak çok tuhaflaştı. Standardın bir sonraki revizyonu int'in long'den daha geniş olduğunu yasadışı ilan etti, ancak int çoğu 64-bit sistemde hala 32 bit.

32-bit sistemlerde bile en az 64 bit olacak şekilde oluşturulduğundan, daha sonra eklenmiş olan long long int olamaz.

Bu yüzden yeni bir tip gerekliydi. Olmasa bile, diğer tüm türler bir dizi veya nesnedeki uzaklıktan başka bir şey ifade ediyordu. 32-64 bitlik göç fiyaskolarından bir ders çıkarsa, bir türün hangi özelliklere sahip olması gerektiği ve farklı programlarda farklı şeyler ifade eden bir özelliği kullanmama konusunda spesifik olması gerekirdi.

4
Davislor

Genel olarak, 0'dan başlayıp yukarı doğru ilerliyorsanız, sizi negatif değer durumlarına sokan taşmayı önlemek için her zaman işaretsiz bir tür kullanın. Bu kritik öneme sahiptir, çünkü dizi sınırlarınız döngü sınırınızın maksimum değerinden daha azsa, ancak döngü maksimum değeriniz türünüzün maksimum değerinden daha büyük olursa, negatif sararsınız ve segmentasyon hatasıyla karşılaşabilirsiniz (SIGSEGV). Bu nedenle, genel olarak, 0'dan başlayan ve yukarı giden bir döngü için hiçbir zaman int kullanmayın. Bir imzasız kullanın.

3
Mark

size_t işaretsiz tamsayı veri türüdür. GNU C Kütüphanesini kullanan sistemlerde, bu işaretsiz int veya imzasız uzun int olacaktır. size_t genellikle dizi indeksleme ve döngü sayımı için kullanılır.

1
Prince

size_t veya herhangi bir imzasız tür, döngü değişkenleri tipik olarak 0'dan büyük veya ona eşit olduğundan döngü değişkeni olarak görülebilir.

Bir size_t object kullandığımız zaman, kullanıldığı tüm bağlamlarda, aritmetik de dahil olmak üzere sadece negatif olmayan değerler istediğimizden emin olmalıyız. Örneğin, aşağıdaki program kesinlikle beklenmeyen bir sonuç verecektir:

// 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
0
bishwas pokharel