Java neden imzalanmamış girişleri desteklemiyor?


374

Java neden imzasız tamsayılar için destek içermiyor?

Beklenmedik derecede büyük girdide taşma üretme olasılığı daha düşük olan kod yazmalarına izin verildiği için garip bir ihmal gibi görünüyor.

Ayrıca, imzasız tamsayıların kullanılması bir tür kendi kendine dokümantasyon olabilir, çünkü imzasız int'in sahip olması amaçlanan değerin asla negatif olması gerektiğini göstermezler.

Son olarak, bazı durumlarda, imzasız tamsayılar, bölme gibi belirli işlemler için daha verimli olabilir.

Bunları dahil etmenin dezavantajı nedir?


137
Bilmiyorum ama bu beni çok kızdırıyor; örneğin ağ kodunu bu şekilde yazmak çok daha zordur.
Tamas Czinege

20
Keşke dil / veritabanı / ... dünyasında sadece iki tür olsaydı: sayı ve dize :)
Liao

5
Ağ kodu yazmak hiç de zor değil. BTW InputStream.read (), imzalanmamış bir bayt döndürür, örneğin imzalı olmayan bir bayt döndürür, böylece ağ örneği bir karışıklık IMHO'dur. Tek kafa karıştırıcısı, imzalı bir değer yazmanın, imzasız bir değer yazmaktan farklı olduğunu varsaymanızdır. yani bayt seviyesinde ne olduğunu gerçekten bilmiyorsanız.
Peter Lawrey

19
@ZachSaw - Bir dil tasarımcısının bu teklifi yaptığını gördüğümde de iki kez yaptım. İşaretsiz bir tam sayıdan daha basit bir şey yoktur. İşaretli tam sayılar karmaşıktır. Özellikle transistör seviyesinde biraz dönmeyi düşündüğünüzde. Ve işaretli bir tam sayı nasıl değişir? Java tasarımcısının boolean mantığını anlayan ciddi bir sorunu olduğu sonucuna vardım.
PP.

8
Bana göre, görüntüler bytedüz 140gri bir seviye veremeyen, ancak doğru değeri elde -116etmeniz gereken herhangi bir görüntü işleme yapmak zorlaşıyor & 0xff.
Matthieu

Yanıtlar:


193

Bu Gosling ve diğerleriyle basitlik üzerine bir röportajdan :

Gosling: Benim için bugünlerde saymadığım bir dil tasarımcısı olarak benim için “basit” in gerçekten anlamı neydi? Bu tanım, örneğin, Java'nın olmadığını ve aslında bu dillerin çoğunun, kimsenin gerçekten anlamadığı şeylerle çok sayıda köşe vakası ile sonuçlandığını söylüyor. Herhangi bir C geliştiricisini imzasız hakkında test edin ve çok yakında neredeyse hiç C geliştiricisinin imzasız olanlarla ne olduğunu, imzasız aritmetiğin ne olduğunu anladığını keşfedersiniz. Bunun gibi şeyler C'yi karmaşık hale getirdi. Java'nın dil kısmı bence oldukça basit. Bakmanız gereken kütüphaneler.


222
Burada belirli bir örnekle Gosling'e katılmam gerekecek (CLR'den daha az değil). Array'a işaretli bir tamsayı uzunluğu değeri veya işaretsiz bir uzunluk vermek daha karmaşık olabilir mi? Bir Dizinin negatif uzunluğa sahip olması imkansızdır, ancak API'mız bunun mümkün olduğunu gösterir.
JaredPar

18
Java'yı basitleştirme argümanı, sonunda dile getirdikleri şablon eksikliğiyle bizi tüm karmaşaya sokan şeyin bir parçası, çünkü alternatifler çok hantaldı. Birinin uygun bir sınıfla imzalanmamış ints'ı destekleyebileceğini düşünüyorum, bunun primerlere ihtiyacı yok
Uri

59
Array indeksleri negatif olamadığı için Java imzasız tamsayılara ihtiyaç duyarsa, dizi dizini dizi boyutundan daha büyük olamayacağı için de alt aralıklara (la Pascal) ihtiyaç duyar.
Wayne Conrad

81
Tamam, sadece işaretsiz tiplere sahip olmamanın avantajlarını anlattı. Şimdi dezavantajları
sayalım

83
Kod sadeliğini dil sadeliğine tercih ederim. Bu yüzden Java'dan nefret ediyorum.
Pijusn

50

Satır aralarını okurken mantığın şöyle bir şey olduğunu düşünüyorum:

  • Java tasarımcıları genellikle mevcut veri türlerinin repertuarını basitleştirmek istedi
  • günlük amaçlar için, en yaygın ihtiyacın imzalı veri türleri için olduğunu hissettiler
  • bazı algoritmaları uygulamak için, imzasız aritmetik bazen gereklidir, ancak bu tür algoritmaları uygulayacak programcılar da imzalı veri türleriyle imzasız aritmetik yaparak "çalışma" bilgisine sahip olacaklardır.

Çoğunlukla bunun makul bir karar olduğunu söyleyebilirim. Muhtemelen:

  • Bu tek bir veri türü için bayt imzasız veya en azından imzalı / imzasız alternatifler sunmuş olabilir (imzalı hale getirmek tutarlılık için iyidir, ancak ne zaman imzalı bir bayta ihtiyacınız vardır?)
  • 'kısa' ile bitirdi (en son ne zaman 16 bitlik imzalı aritmetik kullandınız?)

Yine de, biraz yavaşlama ile, 32 bit'e kadar işaretsiz değerlerle ilgili işlemler çok kötü değildir ve çoğu insanın imzasız 64 bitlik veya karşılaştırmaya ihtiyacı yoktur.


2
Ben de imzasız bayt var isterdim, ama tamsayı türleri arasında tam tutarlılık avantajı imzasız bayt getireceği kolaylık ağır basar şüpheli.
Alan Moore

64
"Günlük amaçlar için, en yaygın ihtiyacın imzalı veri türleri için olduğunu düşünüyorlardı". C ++ kodumda sık sık kendimi "Neden burada imzasız yerine tam olarak imzalı bir tamsayı kullanıyorum?" Diye düşünerek buluyorum. Ben "imzalı" kural yerine istisna olduğunu hissediyorum (tabii ki, bu etki alanına bağlıdır, ancak pozitif tamsayılar doğal sayılar ;-) denilen bir nedeni vardır ).
Luc Touraille

15
imzasız bayt çağrısı için başparmak, görüntü işleme yaparken, imzasız baytlar (olması gerektiği gibi) varsayarak, hata ayıklamak için saatler geçirdi.
Helin Wang

7
ne sıklıkta shortkullanıldığını şaşırtmış olursunuz - defltate / gzip / inflate algoritmaları 16bittir ve şortlara büyük ölçüde güvenirler ... veya en azından short[][ itirafla yereldirler - ancak algoritmanın terrabyte veri taşıma impava]. İkincisi ( short[]), int[]iki kat daha az bellek ve daha az bellek = daha iyi önbellekleme özellikleri, çok daha iyi performans gerektirdiği için önemli bir avantaja sahiptir .
bestsss

8
Belirli bir uygulamada rağmen, gereken ölçmek şort kullanarak gerçek olmasını varsayarak yerine size daha iyi performans verir belirler. Ints yerine şort işlemek için gereken ekstra jiggery-pokery'nin (genellikle işlemcinin 'kullanmayı sevdiği' tiptir) belirli bir uygulamadaki performans için aslında zararlı olabilir. Her zaman değil, ama test etmelisiniz, varsaymayın.
Neil Coffey

19

Bu eski bir soru ve pat kısaca char bahsetti, ben sadece bu yolda bakacak diğerleri için bu genişletmek gerektiğini düşündüm. Java ilkel türlerine daha yakından bakalım:

byte - 8 bit işaretli tam sayı

short - 16 bit işaretli tam sayı

int - 32 bit işaretli tam sayı

long - 64 bit işaretli tam sayı

char - 16 bit karakter (işaretsiz tam sayı)

Her ne kadar chardesteklemediği unsignedaritmetik, aslında bir şekilde tedavi edilebilir unsignedtamsayı. Aritmetik işlemleri açık charbir şekilde tekrar yapmanız gerekir, ancak unsignedsayıları belirtmek için bir yol sağlar .

char a = 0;
char b = 6;
a += 1;
a = (char) (a * b);
a = (char) (a + b);
a = (char) (a - 16);
b = (char) (b % 3);
b = (char) (b / a);
//a = -1; // Generates complier error, must be cast to char
System.out.println(a); // Prints ? 
System.out.println((int) a); // Prints 65532
System.out.println((short) a); // Prints -4
short c = -4;
System.out.println((int) c); // Prints -4, notice the difference with char
a *= 2;
a -= 6;
a /= 3;
a %= 7;
a++;
a--;

Evet, imzasız tamsayılar için doğrudan destek yoktur (açıkçası, doğrudan destek olsaydı, işlemlerimin çoğunu tekrar char'a dökmek zorunda kalmazdım). Ancak, kesinlikle imzasız bir ilkel veri türü vardır. Ben de imzasız bir bayt görmek isterdim, ama bellek maliyetini iki katına ve bunun yerine char kullanmak uygun bir seçenek sanırım.


Düzenle

JDK8 ile orada yeni API'leri olan Longve Integeryardımcı yöntemleri tedavi sağlayan longve intişaretsiz değer olarak değerleri.

  • compareUnsigned
  • divideUnsigned
  • parseUnsignedInt
  • parseUnsignedLong
  • remainderUnsigned
  • toUnsignedLong
  • toUnsignedString

Ek olarak, Guava , tamsayı türlerinde benzer şeyler yapmak için bir dizi yardımcı yöntem sağlar ve bu da tamsayılar için yerel destek eksikliğinin bıraktığı boşluğu kapatmaya yardımcı olur unsigned.


2
Ancak, örneğin, aritmetiği chardestekleyemeyecek kadar küçüktür long.

3
Bu, Java'nın bir dezavantajı olabilir

Baytlar için İmzasız değerleri desteklediklerini umarak. İşleri daha kolay hale getirir.
mixturez

15

Java'nın imzasız türleri veya en az biri var: char imzasız bir kısa. Yani Gosling'in mazereti ne olursa olsun, imzasız başka türlerin bulunmaması gerçekten sadece onun cehaletidir.

Ayrıca Kısa tipler: şortlar multimedya için her zaman kullanılır. Nedeni tek bir 32-bit imzasız uzun 2 örnekleri sığdırmak ve birçok işlemi vectorized olmasıdır. 8 bit veri ve işaretsiz bayt ile aynı şey. 4 veya 8 örneği vektörleştirmek için bir kayıt defterine sığdırabilirsiniz.


37
Evet, eminim Gosling, sizle karşılaştırıldığında Java hakkında çok cahil.
jakeboxer

Java, aritmetiğin doğrudan işaretsiz bayt miktarlarında yapılmasına izin veriyor mu yoksa değerler her zaman tanıtılıyor mu? Depolama için imzasız bir türe sahip olmak, ancak her zaman uyum sağlayacak kadar büyük imzalı bir tür üzerinde aritmetik yapmak, semantik olarak iyi çalışır, ancak "normal" tamsayılarla aynı boyutta olan imzasız türlerde işlemlerin daha pahalı olmasına neden olur.
supercat

2
charKarakterlerden başka bir şey için kullanmak kötü bir stil .
starblue

5
@starblue Tabii ki, ama dilin bir sınırını aşmak bir hack
Basic

14

En kısa sürede imzalı ve imzasız int işler karıştığında başlar bir ifadede karıştırılır ve muhtemelen olacaktır bilgileri kaybedebilirsiniz. Java'yı oturum açmış girişlerle kısıtlamak yalnızca işleri temizler. Bazen bir baytta 8. biti kaçırmama rağmen, imzalı / imzasız tüm iş için endişelenmeme gerek yok.


12
İmzalı / imzasız karıştırma ile ilgili: İmzasız tipleriniz olabilir, ancak karıştırmaya izin vermeyin (veya açık dökümler gerektirir). Yine de gerekli olup olmadığı belli değil.
sleske

2
C ++ 'da static_castonları karıştırmak için çok etrafında serpmek zorunda. Gerçekten dağınık.
Raedwald

4
8. bit orada, sadece işaret olarak kendini saklamaya çalışıyor.
starblue

İşler sadece 32 bit veya daha büyük tiplerle karışıyor. Java'nın bytePascal'da olduğu gibi imzalanmaması için hiçbir neden göremiyorum .
supercat

12
Java'da görüntü işlemeyle ilgili sorun yaşadığınızda, baytların imzasız olmasını beklediğiniz yerde beni görün. O zaman & 0xFFher bayt-int tanıtımının kodu daha da karışık hale getirdiğini bileceksiniz.
bit2shift

12

http://skeletoncoder.blogspot.com/2006/09/java-tutorials-why-no-unsigned.html

Bu adam diyor ki, C standardı imzasız ve imzalı ints içeren işlemleri imzasız olarak nitelendiriyor. Bu, negatif işaretli tam sayıların büyük bir imzasız int içine yuvarlanmasına neden olarak hatalara neden olabilir.


34
Java imzalı tamsayılar da dolaşır. Ne demek istediğini görmüyorum.
foo

8
@foo: İşaretli tamsayıların soruna neden olmadan önce büyümeleri gerekir. Buna karşılık, C'de, herhangi bir negatif tamsayıyı - hatta - -1herhangi bir imzasız quanity ile - hatta sıfır karşılaştırırken sorun yaşayabilir.
supercat

Java imzasız türler içeremezdi, ancak sınırlı sayıda dönüşüm ve karışık operatörlerle (C'de bir işaretçiye 5 ekleyebilme biçimine benziyor, ancak bir işaretçiyi 5 ile karşılaştırılamıyor) . Kapalı bir kadro olduğunda karışık türlerde bir operatör kullanmanın, bu kadronun örtülü kullanımını zorlaması (ve sonuç türünü sonuç türü olarak kullanması), hem .NET hem de .NET'te birçok şüpheli tasarım kararının merkezinde yer alır Java.
supercat

4
Cevabınız üzerinde durmamak için değil, -1"bilinmeyen" yaşta (makalenin önerdiği gibi) olması , "kod kokusunun" klasik örneklerinden biridir . Örneğin siz hesaplamak istiyorsanız, "Alice? Bob daha eski ne kadar" ve A = 25 ve B = -1, sen bir yanıt alırsınız ±26yanlıştır hangi. Bilinmeyen değerlerin doğru kullanımı, Option<TArg>ne Some(25) - Nonezaman döneceğidir None.
bytebuster

11

Java'nın olduğu gibi iyi olduğunu düşünüyorum, imzasız eklemek fazla kazanç olmadan karmaşık hale getirecek. Basitleştirilmiş tamsayı modelinde bile, çoğu Java programcısı temel sayısal türlerin nasıl davrandığını bilmez - sadece yanlış kavramları tutabileceğinizi görmek için Java Puzzlers kitabını okuyun .

Pratik tavsiye gelince:

  • Değerleriniz biraz keyfi boyuttaysa ve uymuyorsa int, kullanın long. longKullanıma uygun olmazlarsa BigInteger.

  • Daha küçük türleri yalnızca yerden tasarruf etmeniz gerektiğinde diziler için kullanın.

  • Tam olarak 64/32/16/8 bite ihtiyacınız varsa, long/ int/ short/ kullanın byteve bölme, karşılaştırma, sağ kaydırma ve döküm hariç işaret biti hakkında endişelenmeyi bırakın.

"C'den Java'ya rasgele bir sayı üretecini taşıma" hakkındaki bu cevaba da bakınız .


5
Evet, hakkı kayması için size arasında seçim yapmak zorunda >>ve >>>sırasıyla imzalı ve imzasız için. Sola kaydırmak sorun değil.
starblue

1
@starblue Aslında ve >>>için çalışmıyor . Örneğin, verim yerine . Başka bir örnek: sonuç verecektir . Tabii ki yapabilirsiniz ama bu bir işlem daha ekler (bitsel ve). shortbyte(byte)0xff>>>10x7fffffff0x7fbyte b=(byte)0xff; b>>>=1;b==(byte)0xffb=(byte)(b & 0xff >> 1);
CITBL

7
“... Basitleştirilmiş modelde bile çoğu Java programcısı temel sayısal türlerin nasıl davrandığını bilmiyor ...” İçimdeki bir şey sadece en küçük ortak paydaya yönelik bir dili kızdırıyor.
Temel

Cevabınızdaki açılış çizgisi, daha fazla komplikasyon ve az kazanç hakkında, 6 yıl sonra makalemde
şey

1
@Nayuki Makaleniz gerçekten çok hoş. Sadece küçük bir açıklama, XOR yerine karşılaştırma operatörleri için 0x80000000 eklemesini kullanacağım, çünkü neden çalıştığını açıklıyor, karşılaştırmanın -MAXINT'ten 0'a çıktığı bitişik bölgeyi kaydırıyor. Bitwise etkisi tamamen aynı.
starblue

6

JDK8 ile onlar için bazı destek var.

Gosling'in endişelerine rağmen Java'da imzasız türlerin tam desteğini görebiliriz.


12
aka "Yani insanlar bunu gerçekten kullanıyor ve başlamak için dahil etmememiz yanlıştı" - ancak yine de bir değişkenin imzalanıp imzalanmadığını bilmek için Java geliştiricilerine güvenmiyoruz - bu yüzden bunları uygulamayacağız VM'de veya imzalı kuzenlerine eşdeğer türlerde.
Temel

6

Bu yazının çok eski olduğunu biliyorum; Ancak ilgiden dolayı, Java 8'de ve daha sonra kullanabileceğiniz inten az 0 değeri ve 2 maksimum değerine sahip işaretsiz 32 bit tam sayı, temsil etmek veri türünü 32 -1. Kullanım Integerkullanımı sınıf intişaretsiz bir tamsayı ve benzeri statik yöntemleri gibi veri türü compareUnsigned(), divideUnsigned()vb eklenen Integertamsayılar için aritmetik operasyonları desteklemek için sınıfta.


4

Orignal Java sürümüne yakın olacaklarını anlatan hikayeler duydum. Meşe, Java'nın öncüsüdür ve bazı spesifik belgelerde, atanmış değerlerden bahsedilmiştir. Ne yazık ki bunlar asla Java diline geçmedi. Herkesin anlayabildiği kadarıyla, muhtemelen bir zaman kısıtlaması nedeniyle, uygulanmadılar.


Bu iyi olurdu ... Gosling röportajından elde edilen kanıtlar, işaretsiz tam sayıların (dışında char) dışarıda bırakıldığını ima ediyor , çünkü tasarımcılar dilin hedefleri göz önüne alındığında ... kötü bir fikir olduklarını düşündüler.
Stephen C

Belgesel kanıtlar da mevcutsa, görgü tanığı ifadelerine asla çok fazla değer katmamak iyi bir fikirdir.
user7610

4

Bir keresinde C ++ standartlar komitesinde, Java'nın imzasız tamsayılardan kaçınmak için doğru kararı verdiğini ima eden bir C ++ kursuna katıldım, çünkü (1) imzasız tamsayılar kullanan programların çoğu imzalı tamsayılarla da yapabilir ve bu daha doğal (2) imzasız tamsayıların kullanılması, tamsayı aritmetik taşması ve imzalı ve imzasız türler arasında dönüştürme yaparken önemli bitleri kaybetme gibi sorunların hatalarını ayıklamak çok kolaydır. İşaretli tamsayıları kullanarak yanlışlıkla 0'dan 1 çıkarırsanız, programınızın daha hızlı çökmesine neden olur ve hatayı bulmayı 2 ^ 32-1'e sarar ve derleyiciler ve statik analiz araçları ve çalışma zamanı denetimleri yapmaktan daha kolay hale getirir. imzasız aritmetik kullanmayı seçtiğiniz için ne yaptığınızı bildiğinizi varsayalım. Ayrıca,

Uzun zaman önce, bellek sınırlı olduğunda ve işlemciler bir kerede 64 bit üzerinde otomatik olarak çalışmadığında, her bit çok daha fazla sayıldı, bu nedenle imzasız baytlara veya şortlara karşı imzalamak aslında çok daha önemliydi ve açık bir şekilde doğru tasarım kararıydı. Bugün sadece imzalı bir int kullanmak neredeyse tüm normal programlama vakalarında fazlasıyla yeterli ve eğer programınızın gerçekten 2 ^ 31 - 1'den büyük değerleri kullanması gerekiyorsa, genellikle uzun bir süre istersiniz. Uzun ürün kullanma bölgesine girdikten sonra, 2 ^ 63-1 pozitif tamsayılarla gerçekten başaramamanızın bir nedeni bulmak daha da zor. 128 bit işlemcilere gittiğimizde sorun daha da az olacaktır.


2

Sorunuz "Java neden imzalanmamış girişleri desteklemiyor?"

Ve sorunuza cevabım, Java'nın tüm ilkel türlerinin olmasını istiyor: bayt , karakter , kısa , int ve uzun , montajda olduğu gibi sırasıyla bayt , kelime , dword ve qword olarak ele alınmalı ve Java operatörleri imzalı char hariç tüm ilkel türlerinde işlemler , ancak sadece char üzerinde sadece 16 bit imzasızdır.

Yani statik yöntemler için varsayalım imzasız işlemleri de hem 32 ve 64 bit.

İmzasız işlemler için statik yöntemleri çağrılabilen son sınıfa ihtiyacınız vardır .

Bu son sınıfı oluşturabilir, istediğiniz adı çağırabilir ve statik yöntemlerini uygulayabilirsiniz.

Statik yöntemlerin nasıl uygulanacağı hakkında hiçbir fikriniz yoksa bu bağlantı size yardımcı olabilir.

Bence, Java değil C ++ diline benzer hiç o takdirde ne imzasız türlerini destekler ne de operatör aşırı yüklenmesini Java hem C ++ ve C den tamamen farklı dil olarak ele alınması gerektiğini düşünüyorum böylece,

Bu arada diller adına da tamamen farklı.

Bu yüzden Java'da C'ye benzer kod yazmanızı önermiyorum ve C ++ 'a benzer kod yazmayı hiç önermiyorum, çünkü Java'da C ++' da daha sonra ne yapmak istediğinizi yapamazsınız, yani kod hiç C ++ gibi olmaya devam etmeyecek ve benim için bu böyle kodlamak, ortadaki stili değiştirmek için kötü.

İmzalı işlemler için de statik yöntemler yazmanızı ve kullanmanızı öneririm, böylece kodda yalnızca imzalı işlemlere ihtiyacınız yoksa, işleçlerin kod karışımında ve hem imzalı hem de imzasız işlemler için statik yöntemler görmezsiniz ve yalnızca operatörleri kullanın.

Ayrıca kısa , int ve uzun ilkel türler kullanmaktan kaçınmanızı ve bunun yerine sırasıyla word , dword ve qword kullanmanızı öneririm ve operatörleri kullanmak yerine imzasız işlemler ve / veya imzalı işlemler için statik yöntemleri çağırmak üzeresiniz.

Yalnızca imzalı işlemleri yapmak ve işleçleri yalnızca kodda kullanmak üzereyseniz , bu ilkel türleri kısa , int ve uzun kullanmakta sorun yoktur .

Aslında kelime , dword ve QWORD do not dilde var, ancak her biri için yeni bir sınıf oluşturup bunu her uygulaması çok kolay olmalıdır:

Sınıf kelimesinin ilk tip tutan kısa sadece sınıf DWORD basit bir tür tutan int sadece sınıf QWORD ilkel tip tutan uzun sadece. Şimdi tüm imzasız ve imzalı yöntemler seçiminiz kadar statik olsun ya da olmasın, her sınıfta uygulayabilirsiniz, yani tüm 16 bit işlemleri hem imzasız hem de imzalı kelime sınıfında anlam adları vererek , hem 32 bit işlemleri hem de imzasız anlam isimleri vererek imzalanan dword imzasız ve üzerinde anlam isimlerini vererek imzalanmış hem sınıf ve tüm 64 bit işlemleri QWORD sınıfına.

Her yöntem için çok fazla farklı ad vermek istemiyorsanız, Java'da aşırı yüklemeyi her zaman kullanabilirsiniz, Java'nın bunu da kaldırmadığını okumak güzel !

8 bit imzalı işlemler için işleçler yerine işleçler ve hiçbir işleçleri olmayan 8 bit işaretsiz işlemler için yöntemler istiyorsanız, Bayt sınıfını oluşturabilirsiniz (ilk 'B' harfinin büyük olduğunu unutmayın, bu nedenle ilkel tip bayt ) ve bu sınıftaki yöntemleri uygular.

Değere göre geçme ve referans olarak geçme hakkında:

Yanılmıyorsam, C # 'da olduğu gibi, ilkel nesneler doğal olarak değere göre geçirilir, ancak sınıf nesneleri doğal olarak referansla geçirilir, böylece Byte , word , dword ve qword türündeki nesneler değere göre değil referansla geçirilir varsayılan olarak. Keşke Java C # gibi yapı nesneleri vardı , bu yüzden tüm Byte , kelime , dword ve qword sınıf yerine yapı olarak uygulanabilir, bu nedenle varsayılan olarak değere göre iletilir ve varsayılan olarak referans olarak değil, C #'daki herhangi bir yapı nesnesi gibi, ilkel türler gibi, varsayılan olarak referans olarak değil, değere göre iletilir, ancak Java, C # 'dan daha kötü olduğundan ve bununla başa çıkmak için, varsayılan olarak değere göre değil, yalnızca başvuru ile iletilen sınıflar ve arabirimler vardır. Bu nedenle , Bayt , kelime , dword ve qword nesnelerini, Java'daki ve C #'daki diğer herhangi bir sınıf nesnesi gibi, referansa göre değil, değere göre iletmek istiyorsanız, kopya oluşturucuyu kullanmanız gerekecektir.

Aklıma gelen tek çözüm bu. İsterdim ki o elimden sadece taşıyıcıların C # aksine hiç kelime, dword ve QWORD ancak Java ne destek typedef ne de kullanmaya ilkel türleri, typedef kullanarak C'nin typedef eşdeğerdir.

Çıktı hakkında:

Aynı bit dizisi için bunları birçok şekilde yazdırabilirsiniz: İkili olarak, ondalık olarak (C printf'de% u anlamı gibi), sekizli (C printf'de% o anlamı gibi), onaltılık olarak (gibi C printf içindeki% x'in anlamı) ve tamsayı olarak (C printf içindeki% d'nin anlamı gibi).

C printf'nin işleve parametre olarak iletilen değişkenlerin türünü bilmediğini unutmayın, bu nedenle printf her bir değişkenin türünü yalnızca işlevin ilk parametresine iletilen char * nesnesinden bilir.

Sınıfların her birinde: Bayt , sözcük , dword ve qword , yazdırma yöntemini uygulayabilir ve printf'in işlevselliğini elde edebilirsiniz, sınıfın ilkel türü imzalanmış olsa bile, aşağıdakileri içeren bazı algoritmaları izleyerek yine de imzasız olarak yazdırabilirsiniz mantıksal ve shift işlemlerinin basamakları çıktıya yazdırmasını sağlar.

Ne yazık ki size verdiğim bağlantı bu yazdırma yöntemlerinin nasıl uygulanacağını göstermiyor, ancak eminim ki bu yazdırma yöntemlerini uygulamak için gereken algoritmalar için google.

Sorunuza cevap verebileceğim ve size önerebileceğim bu kadar.


MASM (Microsoft birleştirici) ve Windows, BYTE, WORD, DWORD, QWORD'i imzasız türler olarak tanımlar. MASM, SBYTE, SWORD, SDWORD, SQWORD için imzalı türlerdir.
rcgldr

1

Çünkü unsignedtip saf kötülüktür.

C'nin unsigned - intürettiği gerçeği unsigneddaha da kötüdür.

İşte beni bir kereden fazla yakan sorunun bir anlık görüntüsü:

// We have odd positive number of rays, 
// consecutive ones at angle delta from each other.
assert( rays.size() > 0 && rays.size() % 2 == 1 );

// Get a set of ray at delta angle between them.
for( size_t n = 0; n < rays.size(); ++n )
{
    // Compute the angle between nth ray and the middle one.
    // The index of the middle one is (rays.size() - 1) / 2,
    // the rays are evenly spaced at angle delta, therefore
    // the magnitude of the angle between nth ray and the 
    // middle one is: 
    double angle = delta * fabs( n - (rays.size() - 1) / 2 ); 

    // Do something else ...
}

Hatayı henüz fark etmediniz mi? İtiraf ediyorum sadece hata ayıklayıcısına girdikten sonra gördüm.

Çünkü nişaretsiz tiptedir size_ttüm ifade n - (rays.size() - 1) / 2değerlendirir olarak unsigned. Bu ifadenin ortadaki ışının imzalı bir konumu olması amaçlanmıştır n: sol taraftaki ortadaki birinci ışın -1 konumuna, sağdaki birinci ışın +1 konumu vb. Olacaktır. abs değeri alarak ve deltaaçı ile çarparak ben nışın ve orta arasındaki açı elde ediyorum .

Ne yazık ki benim için yukarıdaki ifade imzasız kötüyü içeriyordu ve -1 olarak değerlendirmek yerine 2 ^ 32-1 olarak değerlendirdi. Sonraki doublehata bug kapatıldı.

unsignedAritmetiğin yanlış kullanımından kaynaklanan bir veya iki hatadan sonra , ekstra bitin ekstra soruna değip değmeyeceğini merak etmeye başlamak gerekir. unsignedİkili maskeler gibi aritmetik olmayan işlemler için hala kullanılmasına rağmen, aritmetik türlerin herhangi bir kullanımından kaçınmak için mümkün olduğu kadar çok çalışıyorum .


Java'ya "imzasız uzun" eklemek garip olur. Bununla birlikte, daha küçük imzasız türler eklemek sorun yaratmamış olmalıdır. Özellikle "int" den daha küçük türler, sayısal olarak bariz bir şekilde "int" e yükseltilerek kolayca ele alınabilirdi ve "imzasız int", imzalı int ve işaretsiz int içeren işlemlerin teşvik edileceğini söyleyerek ele alınabilirdi her iki işlenen "uzun". Tek sorun durumu, her iki işlenenin tüm değerlerini temsil edebilecek bir tür olmayacağından, imzasız uzun ve imzalı bir miktar içeren işlemler olacaktır.
supercat

@supercat: eğer her operasyona unsigneddönüştürülürse intne işe yarar unsigned? Hiçbir ayırt edici işlevselliği olmayacaktır short. Ve intsadece unsigned+intveya gibi karışık işlemlere dönüştürürseniz unsigned+float, yine de sorununuz var ((unsigned)25-(unsigned)30)*1.0 > 0, bu da unsignedilgili hataların önemli bir nedenidir .
Michael

İmzasız tipler üzerinde yapılan birçok işlem "uzun" hale getirecektir. Sonucu imzasız türlere geri saklarken açık dökümler gerektirilmesi, kısa ve bayt ile aynı sıkıntılara neden olur, ancak tür, sorun olmaması gereken bir hesaplama biçimi yerine çoğunlukla bir depolama biçimidir. Her durumda, "int" den daha kısa işaretsiz tipler, zorluk olmadan "int" e yükselebilmelidir.
supercat

3
Bu cevabı beğenmedim çünkü "imzasız tamsayılar kötüydü ve asla imzalanamayacakları için var olmamalılar" argümanını kullanıyor. İmzasız bir tamsayıdan çıkarmaya çalışan herkes bunu zaten bilmelidir. Okunabilirlik açısından, C'nin takip edilmesi kolay olduğu tam olarak bilinmemektedir. Dahası, "yarı bit" ekstra belaya değmez "argümanı da çok zayıftır. Hata işleme exit(1);gerçekten 'ekstra belaya değer' yerine mi? Gerçekten daha az deneyimli java programcılar kullanarak karışıklık olmayacak güvenlik değer büyük dosyaları açmak mümkün değil unsignedmi?
yyny

2
Bu kodda gördüğüm tek kötü şey n - (rays.size() - 1) / 2. Her zaman ikili işleçleri desteklemelisiniz, çünkü kod okuyucusunun bir bilgisayar programındaki işlem sırası hakkında bir şey alması gerekmez. Geleneksel olarak a + b c = a + (b c) dememiz, kodu okurken bunu kabul edebileceğiniz anlamına gelmez. Ayrıca, hesaplama, döngü olmadan test edilebilmesi için döngü dışında tanımlanmalıdır. Bu, türlerinizin işaretsiz tamsayılardan ziyade sıralanmasını sağlamadığınız bir hatadır. C de türlerinizin sıralandığından emin olmak size kalmış.
Dmitry

0

'C' spesifikasyonunda Java'nın pragmatik nedenlerden dolayı düştüğü ancak geliştirici talebiyle yavaş yavaş geri çekildiği (kapaklar, vb.) Birkaç mücevher var.

İlkinden bahsediyorum çünkü bu tartışma ile ilgili; işaretçi değerlerinin işaretsiz tam sayı aritmetiğine uyması. Ve bu iş parçacığı konusuyla ilgili olarak, Java'nın İmzalı dünyasında İmzasız semantiği korumanın zorluğu.

Gosling'in tasarım ekibine tavsiye etmek için bir Dennis Ritchie alter ego alacak olsaydı, Signed'in "sonsuzda sıfır" vermesini önerebilirdi, böylece tüm adres ofset talepleri önce negatif değerleri ortadan kaldırmak için CEBİRSEL HALKA BOYUTU ekleyecekti.

Bu şekilde, diziye atılan herhangi bir uzaklık hiçbir zaman bir SEGFAULT oluşturamaz. Örneğin, "kendini döndüren döngü" bağlamında imzasız davranış gerektiren çiftlerin RingArray'ı dediğim kapsüllenmiş bir sınıfta:

// ...
// Housekeeping state variable
long entrycount;     // A sequence number
int cycle;           // Number of loops cycled
int size;            // Active size of the array because size<modulus during cycle 0
int modulus;         // Maximal size of the array

// Ring state variables
private int head;   // The 'head' of the Ring
private int tail;   // The ring iterator 'cursor'
// tail may get the current cursor position
// and head gets the old tail value
// there are other semantic variations possible

// The Array state variable
double [] darray;    // The array of doubles

// somewhere in constructor
public RingArray(int modulus) {
    super();
    this.modulus = modulus;
    tail =  head =  cycle = 0;
    darray = new double[modulus];
// ...
}
// ...
double getElementAt(int offset){
    return darray[(tail+modulus+offset%modulus)%modulus];
}
//  remember, the above is treating steady-state where size==modulus
// ...

Yukarıdaki RingArray, kötü niyetli bir istekte bulunan bir kişi denemiş olsa bile, asla negatif bir dizinden 'almaz'. Unutmayın, önceki (negatif) endeks değerlerini istemek için birçok meşru istek vardır.

Not: Dış% modül, meşru talepleri referans alırken, iç% modül, bariz kötülükleri modülden daha negatif negatiflerden maskeler. Bu bir Java + 'da görünecek olsaydı .. + 9 || 8 + .. + spec, o zaman sorun gerçekten "HATA" kendi kendine dönemez bir programcı olur.

Eminim Java imzasız int 'eksikliği' yukarıdaki tek astar ile telafi edilebilir.

Not: Sadece yukarıdaki RingArray oda temizliği ile ilgili bağlam vermek için, yukarıdaki 'get' öğesi işlemiyle eşleşecek bir aday 'set' işlemi:

void addElement(long entrycount,double value){ // to be called only by the keeper of entrycount
    this.entrycount= entrycount;
    cycle = (int)entrycount/modulus;
    if(cycle==0){                       // start-up is when the ring is being populated the first time around
        size = (int)entrycount;         // during start-up, size is less than modulus so use modulo size arithmetic
        tail = (int)entrycount%size;    //  during start-up
    }
    else {
        size = modulus;
        head = tail;
        tail = (int)entrycount%modulus; //  after start-up
    }
    darray[head] = value;               //  always overwrite old tail
}

-2

Talihsiz bir yan etki düşünebilirim. Java gömülü veritabanlarında, 32 bit kimlik alanı ile sahip olabileceğiniz kimlik sayısı 2 ^ 32 değil, 2 ^ 31'dir (~ 4 milyar değil, ~ 2 milyar).


1
Muhtemelen dizileri düşünüyor ve negatif tamsayıları endeks olarak kullanamıyor. Muhtemelen.
SK9

2
Veritabanlarındaki otomatik artış alanları taştığında genellikle Wacko'ya giderler.
Joshua

-8

IMHO'nun nedeni, bu hatayı uygulamak / düzeltmek için çok tembel olmaları / tembel olmalarıdır. C / C ++ programcılarının imzasız, yapı, birleşim, bit bayrağını anlamadığını önermek ... Sadece mantıklı.

Ether, bu dili gerçek bir bilgi olmadan, la C programlamaya başlayarak, bir temel / bash / java programcısıyla konuşuyordunuz ya da sadece kendi zihninizden bahsediyorsunuz. ;)

Her gün dosya veya donanımdan formatta uğraştığınızda ne düşündüklerini sormaya başlarsınız.

Burada iyi bir örnek, imzasız bir baytı kendi kendine dönen bir döngü olarak kullanmaya çalışmak olabilir. Son cümleyi anlamayanlar için, dünyada nasıl bir programcı diyorsunuz.

DC


34
Sadece tekmeler için, Google "kendi kendine dönen döngü" ifadesini kullanır. Açıkçası , Denis Co dünyada kendini programcı olarak adlandırmaya layık görülen tek kişidir :-)
Stephen C

6
Bu cevap o kadar kötü ki komik
Nayuki
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.