unsigned int ve size_t


492

Modern C ve C ++ kodu size_tyerine int/ unsigned inthemen hemen her yerde kullanmak gibi görünüyor - C string fonksiyonları için parametrelerden STL. Bunun sebebini ve sağladığı faydaları merak ediyorum.

Yanıtlar:


388

size_tTipi sonucudur işaretsiz tamsayı türüdür sizeofoperatör (ve offsetofo sistem işleyebilir büyük nesne (örneğin 8Gb statik dizi) boyutunu içerecek yeterince büyük olması sağlanır, böylece operatör).

size_tTip bir daha, daha büyük eşit veya daha küçük olabilir unsigned int, ve derleyici optimizasyon için bu konuda varsayımları yapabiliriz.

Daha kesin bilgileri, taslağı internette pdf formatında mevcut olan C99 standardı, bölüm 7.17'de veya pdf taslağı olarak da bulunan C11 standardı, kısım 7.19'da bulabilirsiniz .


50
Hayır! Büyük (büyük olmayan) bellek modeliyle x86-16'yı düşünün: İşaretçiler uzaktır (32 bit), ancak tek tek nesneler 64k ile sınırlıdır (bu nedenle size_t 16 bit olabilir).
dan04

8
"en büyük nesnenin boyutu" kötü ifadeler değil, kesinlikle doğrudur. Bir nesnenin altısı adres alanından çok daha sınırlı olabilir.
gnasher729

3
"Derleyiciniz bu konuda varsayım yapabilir": Umarım derleyici temsil edebilecek değerlerin tam aralığını bilirsize_t ! Değilse, kim yapar?
Marc van Leeuwen

4
@Marc: Derleyicinin bu bilgi ile bir şeyler yapabilmesinin daha önemli olduğunu düşünüyorum .

8
Keşke daha popüler olan bu tür bir başlık dosyasının eklenmesini gerektirmiyordu.
user2023370


73

Kısacası, size_tasla olumsuz değildir ve performansı en üst düzeye çıkarır çünkü hedef platformda mümkün olan en büyük nesnenin boyutunu temsil etmek için yeterince büyük - ancak çok büyük olmayan - imzasız tam sayı türü olarak tanımlanır.

Boyutlar asla negatif olmamalıdır ve gerçekten size_timzasız bir tiptir. Ayrıca, size_timzasız olduğu için, işaretli tamsayıdaki diğer tüm bitler gibi, işaret bitini büyüklüğü temsil etmek için kullanabileceğimizden, karşılık gelen işaretli türden kabaca iki kat daha büyük sayıları saklayabilirsiniz. Bir bit daha kazandığımızda, temsil edebileceğimiz sayı aralığını yaklaşık iki kat artarız.

Peki, neden sadece bir unsigned int? Yeterince büyük sayıları tutamayabilir. unsigned int32 bitlik bir uygulamada , temsil edebileceği en büyük sayı 4294967295. IP16L32 gibi bazı işlemciler 4294967295bayttan daha büyük nesneleri kopyalayabilir .

Peki, neden kullanmıyorsunuz unsigned long int? Bazı platformlarda bir performans ücretini etkiler. Standart C, longen az 32 bit işgal etmeyi gerektirir . Bir IP16L32 platformu, her bir 32 bit uzunluğunu bir çift 16 bit kelime olarak uygular. Bu platformlardaki hemen hemen tüm 32 bit operatörler, daha fazla olmasa da iki talimat gerektirir, çünkü iki 16 bitlik parçadaki 32 bit ile çalışırlar. Örneğin, 32 bit uzunluğunu taşımak genellikle iki makine talimatı gerektirir - her biri 16 bitlik yığınları taşımak için bir tane.

Kullanmak size_tbu performans ücretini önler. Göre bu fantastik makalede , "Tür size_ttipik bazı işaretsiz tamsayı türü için bir takma ad bir typedef unsigned intveya unsigned longancak hatta unsigned long long. Ama needed-- daha büyük - Her Standart C uygulaması yeterince büyük olduğunu işaretsiz tamsayı seçmek gerekiyordu hedef platformda mümkün olan en büyük nesnenin boyutunu temsil etmek. "


1
Bu konuda uzun zaman sonra yorum yapmak için üzgünüm, ama imzasız bir int'in tutabileceği en büyük sayıyı doğrulamak zorunda kaldım - belki de terminolojinizi yanlış anlıyorum, ama imzasız bir int'in tutabileceği en büyük sayının 4294967295, 65356 olduğunu düşünüyorum. imzasız kısa bir maksimum.
Mitch

İmzasız int'iniz 32 bit kaplıyorsa, evet, tutabileceği en büyük sayı 2 ^ 32 - 1'dir (4294967295 (0xffffffff)). Başka sorunuz var mı?
Gül Perrone

3
@Mitch: Bir kutuda temsil unsigned intedilebilecek ve bir sistemden diğerine değişebilen en büyük değer . En azından olması gerekiyor 65536, ancak bazı sistemlerde yaygın olarak 4294967295ve 18446744073709551615(2 ** 64-1) olabilir .
Keith Thompson

1
16 bit imzasız int'in içerebileceği en büyük değer 65536 değil 65535'tir. 65536 ile küçük ama önemli bir fark, 16 bit imzasız int'te 0 ile aynıdır.
Sie Raybould

1
@ gnasher729: C ++ standardından emin misiniz? Bir süre aradıktan sonra, sadece tamsayı aralıkları (hariç unsigned char) hakkındaki tüm mutlak garantileri kaldırdığı izlenimi altındayım . Standart hiçbir yerde '65535' veya '65536' dizesini içermiyor gibi görünüyor ve '+32767' yalnızca bir notta temsil edilebilecek en büyük tam sayı olarak (1.9: 9) oluşur int; INT_MAXbundan daha küçük olamaz bile garanti verilmez !
Marc van Leeuwen

51

Size_t türü, sizeof operatörü tarafından döndürülen türdür. Ana makinede desteklenen herhangi bir bellek aralığının boyutunu bayt cinsinden ifade edebilen işaretsiz bir tam sayıdır. (Tipik olarak), ptrdiff_t öğesinin, sizeof (ptrdiff_t) ve sizeof (size_t) eşit olacak şekilde işaretli bir tam sayı değeri olmasıyla ilgilidir.

C kodu yazarken , bellek aralıkları ile uğraşırken daima size_t kullanmalısınız.

Diğer yandan int türü temel olarak ana makinenin tamsayı aritmetiğini en verimli şekilde gerçekleştirmek için kullanabileceği (işaretli) tamsayı değerinin boyutu olarak tanımlanır. Örneğin, birçok eski PC tipi bilgisayarda sizeof (size_t) değeri 4 (bayt) olur, ancak sizeof (int) 2 (bayt) olur. 16 bit aritmetik 32 bit aritmetikten daha hızlıydı, ancak CPU 4 GiB'ye kadar (mantıksal) bellek alanını işleyebiliyordu.

İnt türünü yalnızca verimliliği önemsediğiniz zaman kullanın çünkü gerçek hassasiyeti hem derleyici seçeneklerine hem de makine mimarisine bağlıdır. Özellikle C standardı aşağıdaki değişmezleri belirtir: sizeof (char) <= sizeof (kısa) <= sizeof (int) <= sizeof (uzun), bu ilkel tipler.

Not: Bu Java ile aynı DEĞİLDİR (aslında 'char', 'byte', 'short', 'int' ve 'long' türlerinin her biri için bit hassasiyetini belirtir).


int'in fiili tanımı, 16 makinede 16 bit ve daha büyük bir şeyde 32 bit olmasıdır. İnt'in 32 bit genişliğinde olduğunu varsaymak için çok fazla kod yazılmıştır, bunu şimdi değiştirmek için ve sonuç olarak insanlar belirli bir şey istiyorlarsa daima size_t veya {, u} int {8,16,32,64} _t kullanmalıdırlar - - önlem olarak, insanlar bunları tamsayı tamsayı türleri yerine her zaman kullanmalıdır.
Daha net

3
"Ana makinede desteklenen herhangi bir bellek aralığının boyutunu bayt cinsinden ifade edebilen işaretsiz bir tam sayıdır." -> No. size_therhangi bir nesnenin boyutunu temsil edebilir (örneğin: sayı, dizi, yapı). Tüm bellek aralığı aşılabilirsize_t
chux - Monica'yı eski durumuna döndür

"C kodu yazarken bellek aralıklarıyla uğraşırken daima size_t kullanmalısınız." - Bu her dizinin her dizinin olması gerektiği anlamına gelir size_t- Umarım bunu demek istemezsiniz. Çoğu zaman, adres alanının + taşınabilirliğinin önemli olduğu dizilerle ilgilenmiyoruz. Bu gibi durumlarda alırsınız size_t. Diğer her durumda indeksleri (imzalı) tamsayılardan çıkarırsınız. Çünkü imzasızların beklenmedik taşma davranışından kaynaklanan karışıklık (uyarı olmadan gelir), diğer durumlarda ortaya çıkabilecek taşınabilirlik sorunlarından daha yaygın ve daha kötüdür.
johannes_lalala

23

Size_t türü, olası herhangi bir nesnenin boyutunu depolayacak kadar büyük olmalıdır. İmzasız int'in bu koşulu yerine getirmesi gerekmez.

Örneğin, 64 bit sistemlerde int ve unsigned int 32 bit genişliğinde olabilir, ancak size_t, 4G'den büyük sayıları depolayacak kadar büyük olmalıdır


38
"nesne" standart tarafından kullanılan dildir.
R .. GitHub BUZA YARDIMCI DURDUR

2
Bence size_tderleyici bir X tipi kabul edebilirse, sizeof (X) 4G'den daha büyük bir değer verir. Çoğu derleyici reddeder typedef unsigned char foo[1000000000000LL][1000000000000LL]ve foo[65536][65536];belgelenmiş bir uygulama tanımlı sınırı aşarsa meşru bir şekilde reddedilebilir.
Supercat

1
@MattJoiner: İfadeler iyi. "Nesne" hiç de belirsiz değil, daha ziyade "depolama bölgesi" anlamına gelir.
Yörüngedeki Hafiflik Yarışları

4

Glibc 0.02 el kitabından alıntı, konuyu araştırırken de geçerli olabilir:

2.4 sürümünden önce GCC'nin size_t türü ve sürümleriyle ilgili potansiyel bir sorun var. ANSI C size_t öğesinin her zaman imzasız bir tip olmasını gerektirir. Mevcut sistemlerin başlık dosyalarıyla uyumluluk için GCC, stddef.h' to be whatever type the system'ssys / types.h dosyasında size_t öğesini tanımlar. Sys / types.h dosyasında size_t öğesini tanımlayan çoğu Unix sistemi, bunu imzalı bir tür olarak tanımlar. Kitaplıktaki bazı kodlar size_t öğesinin imzasız tür olmasına bağlıdır ve imzalanmışsa düzgün çalışmaz.

Size_t öğesinin imzasız olmasını bekleyen GNU C kütüphane kodu doğrudur. Size_t öğesinin işaretli tür olarak tanımı yanlış. 2.4 sürümünde, GCC'nin fixincludes' script will massage the system'sboyut_t değerini her zaman imzasız bir tür olarak ve sys / types.h ' olarak tanımlamasını planlıyoruz.

Bu arada, bu soruna geçici olarak GCC'ye GNU C kütüphanesini derlerken size_t için imzasız bir tür kullanmasını söyleyerek çalışırız. “configure”, GCC'nin size_t için kullandığı türü otomatik olarak algılar ve gerekirse geçersiz kılmayı ayarlar.


2

Derleyicim 32 bit olarak ayarlanmışsa, size_ttypedef için başka bir şey değildir unsigned int. Derleyicim 64 bit olarak ayarlanmışsa, size_ttypedef'den başka bir şey değildir unsigned long long.


1
unsigned longBazı işletim sistemlerinde her iki durum için de tanımlanabilir .
StaceyGirl

-4

size_t bir işaretçinin boyutudur.

Yani 32 bit veya ortak ILP32 (tamsayı, uzun, işaretçi) model size_t 32 bittir. ve 64 bit veya ortak LP64 (uzun, işaretçi) model boyutu_t 64 bittir (tamsayılar hala 32 bittir).

Başka modeller var ama bunlar g ++ 'ın kullandığı modeller (en azından varsayılan olarak)


15
size_ther ne kadar yaygın olarak olsa da, bir işaretçi ile aynı boyutta olması gerekmez. Bir işaretçi bellekteki herhangi bir yeri gösterebilmelidir; size_tyalnızca en büyük tek nesnenin boyutunu temsil edecek kadar büyük olmalıdır.
Keith Thompson
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.