Tamsayı veri türü olarak çok mu kullanılıyor?


9

Uygulama geliştiricilerinin çoğu imzasız tamsayıları kullanmak istedikleri yerlerde imzalı tamsayılar kullanıyor mu? Bunu her zaman yaparım, iş arkadaşlarım da öyle. Ben (Delphi VCL dışında) diğer kapsamlı kod tabanları bir sürü görmedim ve internette örnekleri genellikle tamsayı kullanın. Oysa VCL geliştiricileri kendi veri türlerini kullanırlar (değişkenleri bildirmek için en tembel olmayan yol budur).

Bir şey böyle kod hakkında biraz korkunç görünüyor

TStuffRec = record
   recordID : Integer;
   thingID : Integer;
   otherThingID : Integer;
end;

ne zaman yazılabilir

TStuffRec = record
   recordID : Cardinal;
   thingID : Cardinal;
   otherThingID : Cardinal;
end;

İşlevsel olarak, bu kayıtlar neredeyse her zaman aynı şekilde çalışır (ve umarım 64 bit Delphi'de bile aynı şekilde çalışmaya devam eder). Ancak çok büyük sayılarda dönüşüm sorunları olacaktır.

Ancak imzasız ints kullanmanın dezavantajları vardır. Temelde ikisini karıştırmanın ne kadar can sıkıcı olmasından kaynaklanıyor.

Asıl soru şu ki, bu gerçekten düşünülen veya en iyi uygulamalara dahil edilen bir şey mi? Genellikle geliştiriciye mi kalmış?


5
Peter, sadece Delphi'ye özel cevaplar mı arıyorsunuz?
Adam Lear

3
@Anna Delphi veri tiplerinin nasıl çalıştığını anlamak en mükemmel cevabı verir. C programcılarının bu soruyu anlayabileceklerinden ve cevaplayabileceklerinden eminim.
Peter Turner

Yanıtlar:


9

Ben Delphi tüm bu kadar imzasız tamsayı türleri kullanmamanın bir nedeni, onlar imzalı tamsayı ile karıştırıldığında sorunları oluşturabilirsiniz olmasıdır. İşte beni bir kez ısırmış olan:

for i := 0 to List.Count - 1 do
  //do something here

iİmzasız bir tamsayı olarak ilan etmiştim (sonuçta, 0 ile başlayan bir listeye bir indeks, asla negatif olmamalı, değil mi?), Ancak List.Count0 olduğunda , döngüyü beklendiği gibi kısa devre yapmaz çünkü 0 - 1çok yüksek bir pozitif sayı olarak değerlendirilir. Hata!

İmzalı ve imzasız tamsayıları karıştırmanın doğasında var olan potansiyel güvenlik sorunları ve aralık sorunları arasında (bundan daha büyük pozitif sayılara ihtiyacınız varsa , çok high(signed whatever)daha büyük pozitif sayılara da ihtiyaç duyacaksınız high(unsigned whatever), bu nedenle aynı boyutta imzalıdan imzasıza geçmek yerine bir sonraki büyük boyuta kadar genellikle doğru eylemdir,) Çoğu veriyi temsil ederken imzasız tamsayılar için çok fazla kullanım bulamadım.


2
Biraz ilgili olarak, gerekenden daha küçük bir veri türü kullanmanın en önemli risklerinden biri (sadece imzasız ve imzalı olanların aksine), çıkış koşulu planladığınızdan daha büyükse, gerçekten sonsuz bir döngü elde edebilmenizdir. sayaç tekrar tekrar taşar. Görünüşte aptalca geliyor, ama bir keresinde olası her bayt değerinde döngü yapması gereken bir program yazdım ve sonunda kendimi bir bayt sayacıyla yapmanın mümkün olmadığına ikna etmek yaklaşık 15 dakika sürdü.
Aaronaught

@Aaronaught: Delphi'de değil. (En azından yerleşik taşma denetimini devre dışı bırakmak gibi aptalca bir şey yapmadığınız sürece değil.) Sayaç taştığında sonsuz bir döngü yerine bir istisna ile karşılaşırsınız. Hala bir hata, ama takip etmek çok daha kolay.
Mason Wheeler

Öyle diyorsan. Ben her zaman Delphi taşma kontrol devre dışı; hash kodları ve sağlama toplamları gibi şeylerden yanlış pozitifler ile durmadan bombalandıktan sonra, o "özellik" ten tamamen vazgeçtim. Ama sanırım haklısın, bu belirli hatayı yakalamış olurdu.
Aaronaught

@Aaronaught: Evet, özellikle taşması ve sarılması için tasarlanmış karma kodlar ve sağlama toplamları gibi şeyler için devre dışı bırakmak istersiniz. Ama edilir genel amaçlı hesaplamalar için değil taşması ve çevresini sarmak üzere tasarlanmış, önemli bir güvenlik özelliğidir var ve onu kapatarak tür bir emniyet kemeri olmadan sürüş gibidir.
Mason Wheeler

Belki de unutmuştunuz, ancak taşma kontrolü ve derleyici yönergeleri Delphi'nin eski sürümlerinde inanılmaz derecede hata yapıyordu. Hatalı bir taşmayı bildirmek için hata ayıklayıcının doğrudan bir {$ O -} / {$ O +} bloğunun ortasında durduğunu gördükten sonra saçlarımı birden çok kez yırtıldığını canlı olarak hatırlıyorum. Bir süre sonra artık dayanamadım ve sadece küresel olarak devre dışı bıraktım. Yine, evet, bu sorunu yakalamış olurdu, ama yine de yanlış pozitif sayısına değdiğini düşünmüyorum. Elbette her birine kendi!
Aaronaught

3

Dürüst olmak gerekirse, Tamsayıları alışkanlıkla kullanma eğilimindeyim. Çoğu durum için yeterince büyük aralıklar sundukları ve negatif değerlere (-1 gibi) izin verdik. Gerçekten de, bayt / word / shortint kullanmak çoğu zaman daha uygun olur. Şimdi düşünerek şu noktalara odaklanabilirim:

  • Perspektif. Tilemap boyutu 192x192 fayans ile sınırlıdır, bu yüzden fayans ve döngüler için bayt kullanabilirim. Ancak harita boyutu artırılacaksa, her kullanımdan geçmeli ve örneğin kelime ile değiştirmeliyim. Harita dışı nesnelere izin vermem gerektiğinde, küçültmeye geçmek için tekrar gitmem gerekir.

  • Döngüler. Ben sık sık "i" bayt ve Count = 0 döngü olur 0 ile 255 çalışır. "İ: = 0'dan Count-1" bir döngü yazmak, ne olur.

  • Uniforming. Hatırlamak ve uygulamak "var i: integer;" her durumda durdurmak ve "Hm .. burada 0..120 aralığı ile ilgileniyoruz .. bayt .. hayır, bekleyin, başlatılmamış için -1 gerekebilir .. kısa .. bekle .. ne 128 ise yeterli değil .. Arrgh! " veya "Neden burası küçük değil, kısa değil?"

  • Birleştirme. İki veya daha fazla sınıfı bir araya getirmem gerektiğinde, amaçları için farklı veri türleri kullanıyor olabilirler, daha geniş türler kullanmak gereksiz dönüşümleri atlamayı sağlar.

  • -1. Değerler 0..n-1 aralığında olsa bile, sık sık "1 değer / bilinmeyen / başlatılmamış / boş" değer ayarlamam gerekir.

Tamsayıların kullanılması, tüm bu sorunların atlanmasına, ihtiyaç duyulmadığında düşük seviye optimizasyonun unutulmasına, daha yüksek seviyeye çıkılmasına ve daha gerçek sorunlara odaklanılmasına izin verir.

PS Diğer türleri ne zaman kullanırım?

  • Sayaçlar, asla negatif değildirler ve sınıflarının dışında salt okunurdurlar.
  • Performans / Bellek nedenleri, belirli yerlerde daha kısa veri türleri kullanmaya zorlar.

1

En iyi uygulama, kullanılan veriye (beklenen veri) uygun bir veri türü kullanmaktır.

C # örnekler: Yalnızca 0 - 255'i desteklemem gerekirse, bir bayt kullanırdım.

1.000.000 negatif ve pozitif desteklemem gerekiyorsa, int.

4,2 milyardan büyük, sonra uzun kullanın.

Doğru türü seçerek, program en iyi miktarda belleği kullanacak ve farklı türlerde farklı miktarda bellek kullanacaktır.

İşte MSDN'den bir C # int başvurusu.

int 
 -2,147,483,648 to 2,147,483,647
 Signed 32-bit integer

uint 
 0 to 4,294,967,295
 Unsigned 32-bit integer

long 
 -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
 Signed 64-bit integer

ulong 
 0 to 18,446,744,073,709,551,615
 Unsigned 64-bit integer

C # (veya genel olarak .net) uzun ve ulong 128 bitlik bir makinede 128 bit olur mu? Çünkü Delphi'de, Integerveri türü 32 bitlik bir makinede 32 bit ve görünüşte 64 bitlik bir makinede 64 bit olacaktır.
Peter Turner

1
@Peter Turner: Hayır, C # ' intda System.Int32, kod hangi makinede çalışırsa çalışsın , sadece bir kısayol .
nikie

@nikie, bunun gibi bir type int System.Int32şey mi? Çerçevenin gelecekteki bir sürümünde bu kadar kolay değiştirilebilir mi?
Peter Turner

Peter Turner / nikie (sizeof (int) .ToString ()); ==> 4 döndürür (sizeof (Int64) .ToString ()); ==> 8 döndürür 64bit Windows işletim sistemimde. Nikie olarak, istatistikler, bir int gerçekten adil ve Int32.
Jon Raynor

1
Dikkat edilmesi gereken bir nokta, tüm türlerin Ortak Dil Spesifikasyonu ile uyumlu olmadığıdır . uintbu tür uyumlu olmayan türlerden biridir, yani kütüphanenin yazıldığı dilin dışındaki .NET dillerinde bu API'yi kullanma yeteneğini kırmamak için herkese açık olarak açık API'da kullanılmaması gerektiği anlamına gelir. API'nin kendisi intnerede uintkullanacağını kullanıyor .
Adam Lear

1

İşaretsiz tamsayı türleri yalnızca kardinal sayıları temsil ettikleri dillerde kardinal sayıları temsil etmek için kullanılmalıdır. C'yi çalıştıran bilgisayarların çalışma şekli nedeniyle, imzasız tamsayı türleri mod-2 ^ n cebir halkalarının üyeleri olarak davrandı (taşan hesaplamalar tahmin edilebilir bir şekilde "sarılacağı" anlamına gelir) ve dil birçok durumda bu türlerin böyle bir davranış, kardinal sayıların veya matematiksel tamsayıların davranışıyla tutarsız olsa bile, soyut cebirsel halkalar gibi davranması gerekir.

Bir platform, kardinal sayılar ve cebirsel halkalar için ayrı tipleri tamamen destekliyorsa, kardinal sayıların kardinal sayı tipleri (ve halka tipleri kullanılarak sarılması gereken şeyler) kullanılarak işlenmesini öneririm. Bu tür türler yalnızca imzalı türlerin boyutunun iki katını depolamakla kalmaz, aynı zamanda bu türden bir parametre alan bir yöntemin negatif olup olmadığını kontrol etmesi gerekmez.

Bununla birlikte, kardinal sayı tiplerinin göreceli eksikliği göz önüne alındığında, genellikle hem matematiksel tam sayıları hem de kardinal sayıları temsil etmek için tamsayıları kullanmak en iyisidir.

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.