Mengapa Java tidak mendukung int yang tidak ditandatangani?

374

Mengapa Java tidak menyertakan dukungan untuk bilangan bulat tak bertanda?

Bagi saya kelihatannya merupakan kelalaian aneh, mengingat bahwa mereka memungkinkan seseorang untuk menulis kode yang cenderung menghasilkan kelebihan pada input besar yang tidak terduga.

Lebih jauh lagi, menggunakan bilangan bulat yang tidak ditandatangani dapat menjadi bentuk dokumentasi diri, karena mereka menunjukkan bahwa nilai yang ingin disimpan oleh unsigned int tidak pernah dianggap negatif.

Terakhir, dalam beberapa kasus, bilangan bulat tak bertanda dapat lebih efisien untuk operasi tertentu, seperti divisi.

Apa kerugiannya termasuk ini?

dsimcha
sumber
137
Saya tidak tahu tetapi itu mengganggu saya; misalnya jauh lebih sulit untuk menulis kode jaringan dengan cara ini.
Tamas Czinege
20
Saya berharap hanya ada dua jenis dalam bahasa / basis data / ... dunia: angka dan string :)
Liao
5
Menulis kode jaringan sama sekali tidak sulit. BTW InputStream.read (), mengembalikan byte yang tidak ditandai, bukan yang sudah ditandatangani misalnya jadi contoh jaringan adalah IMHO kebingungan. Satu-satunya yang membingungkan adalah Anda menganggap bahwa menulis nilai yang ditandatangani berbeda dengan menulis yang tidak ditandatangani. yaitu jika Anda tidak benar-benar tahu apa yang terjadi pada level byte.
Peter Lawrey
19
@ ZachSaw - Saya juga melakukan pengambilan ganda ketika saya melihat seorang perancang bahasa membuat kutipan itu. Tidak ada yang lebih sederhana dari integer yang tidak ditandai. Bilangan bulat yang ditandatangani rumit. Terutama ketika Anda mempertimbangkan sedikit memutar-mutar di tingkat transistor. Dan bagaimana bilangan bulat yang ditandatangani bergeser? Saya harus menyimpulkan bahwa perancang Jawa memiliki masalah serius dalam memahami logika boolean.
PP.
8
Bagi saya itu menjadi lebih sulit untuk melakukan pemrosesan gambar dengan gambar bytetidak bisa memberikan 140tingkat abu-abu lurus tetapi -116yang Anda butuhkan & 0xffuntuk mendapatkan nilai yang benar.
Matthieu

Jawaban:

193

Ini dari wawancara dengan Gosling dan lainnya , tentang kesederhanaan:

Gosling: Bagi saya sebagai perancang bahasa, yang saya tidak benar-benar menganggap diri saya sebagai hari ini, apa yang "sederhana" benar-benar berarti akhirnya bisa saya harapkan J. Random Developer untuk memegang spec di kepalanya. Definisi itu mengatakan bahwa, misalnya, Java tidak - dan pada kenyataannya banyak dari bahasa ini berakhir dengan banyak kasus sudut, hal-hal yang benar-benar tidak dipahami oleh siapa pun. Tanyai setiap pengembang C tentang unsigned, dan segera Anda menemukan bahwa hampir tidak ada pengembang C yang benar-benar memahami apa yang terjadi dengan unsigned, apa aritmatika unsigned itu. Hal-hal seperti itu membuat C kompleks. Bagian bahasa Jawa, saya pikir, cukup sederhana. Perpustakaan yang harus Anda cari.

Uri
sumber
222
Saya harus tidak setuju dengan Gosling di sini dengan contoh spesifik (dari CLR tidak kurang). Apa yang lebih membingungkan dengan memberikan nilai panjang integer yang ditandatangani atau panjang yang tidak ditandatangani? Tidak mungkin bagi Array memiliki panjang negatif, namun API kami menunjukkan itu mungkin.
JaredPar
18
Argumen membuat Java sederhana adalah bagian dari apa yang membuat kita masuk ke dalam kekacauan dengan kurangnya template yang akhirnya mereka bawa ke dalam bahasa karena alternatifnya sangat rumit. Saya pikir seseorang dapat mendukung int unsigned dengan kelas yang sesuai, meskipun, tidak perlu prima
Uri
59
Jika Java membutuhkan bilangan bulat yang tidak ditandai karena indeks Array tidak boleh negatif, maka itu juga membutuhkan subrange (a la Pascal) karena indeks array tidak boleh lebih besar dari ukuran array.
Wayne Conrad
81
Oke, dia hanya mengatakan keuntungan dari tidak memiliki tipe yang tidak ditandatangani. Sekarang mari kita hitung kerugiannya ...
Moshe Revah
83
Saya lebih suka kesederhanaan kode daripada kesederhanaan bahasa. Itu sebabnya saya membenci Jawa.
Pijusn
50

Membaca yang tersirat, saya pikir logikanya seperti ini:

  • umumnya, desainer Java ingin menyederhanakan repertoar tipe data yang tersedia
  • untuk keperluan sehari-hari, mereka merasa bahwa kebutuhan paling umum adalah untuk tipe data yang ditandatangani
  • untuk mengimplementasikan algoritma tertentu, kadang-kadang diperlukan aritmatika unsigned, tetapi jenis programer yang akan mengimplementasikan algoritma seperti itu juga akan memiliki pengetahuan untuk "bekerja sama" melakukan aritmatika unsigned dengan tipe data yang ditandatangani.

Sebagian besar, saya akan mengatakan itu adalah keputusan yang masuk akal. Mungkin, saya akan memiliki:

  • membuat byte tidak ditandatangani, atau setidaknya telah menyediakan alternatif yang ditandatangani / tidak ditandatangani, mungkin dengan nama yang berbeda, untuk tipe data yang satu ini (membuatnya ditandatangani baik untuk konsistensi, tetapi kapan Anda memerlukan byte yang ditandatangani?)
  • dihilangkan dengan 'short' (kapan terakhir kali Anda menggunakan aritmatika bertanda 16-bit?)

Namun, dengan sedikit kludging, operasi pada nilai yang tidak ditandatangani hingga 32 bit tidak terlalu buruk, dan kebanyakan orang tidak perlu pembagian atau perbandingan 64-bit yang tidak ditandatangani.

Neil Coffey
sumber
2
Saya juga ingin memiliki byte yang tidak ditandai, tetapi saya curiga keuntungan dari konsistensi lengkap di antara tipe integer melebihi kenyamanan yang dihasilkan oleh byte yang tidak ditandatangani.
Alan Moore
64
"Untuk keperluan sehari-hari, mereka merasa bahwa kebutuhan paling umum adalah untuk tipe data yang ditandatangani". Dalam kode C ++ saya, saya lebih sering menemukan diri saya berpikir "Kenapa saya menggunakan integer yang ditandatangani di sini, bukannya yang tidak ditandatangani ?!". Saya memiliki perasaan bahwa "ditandatangani" adalah pengecualian daripada aturan (tentu saja, itu tergantung pada domain, tetapi ada alasan mengapa bilangan bulat positif disebut alam nomor ;-)).
Luc Touraille
15
jempol untuk panggilan untuk byte yang tidak ditandatangani, ketika melakukan pemrosesan gambar, dengan asumsi byte tidak ditandatangani (sebagaimana mestinya), membuat saya menghabiskan waktu berjam-jam untuk debugging.
Helin Wang
7
Anda akan terkejut seberapa sering shortdigunakan - algoritma defltate / gzip / inflate adalah 16bit dan mereka sangat bergantung pada celana pendek ... atau setidaknya short[][diakui itu asli - namun java impl dari algoritma ini membawa terrabytes data]. Yang terakhir ( short[]) memiliki keuntungan yang signifikan int[]karena membutuhkan memori dua kali lebih sedikit dan lebih sedikit memori = properti caching yang lebih baik, kinerja yang jauh lebih baik.
bestsss
8
Meskipun dalam aplikasi tertentu, Anda harus mengukur apakah menggunakan celana pendek memberi Anda kinerja yang lebih baik daripada menganggap itu benar. Ada kemungkinan bahwa jiggery-pokery tambahan yang diperlukan untuk memanipulasi celana pendek daripada int (yang biasanya merupakan tipe yang 'suka digunakan' prosesor) sebenarnya dapat merusak kinerja dalam aplikasi tertentu. Tidak selalu, tetapi Anda harus menguji, tidak berasumsi.
Neil Coffey
19

Ini adalah pertanyaan yang lebih tua dan tepuk memang menyebutkan char, saya hanya berpikir saya harus memperluas ini untuk orang lain yang akan melihat ini di jalan. Mari kita lihat lebih dekat tipe-tipe primitif Java:

byte - Bilangan bulat bertanda 8-bit

short - Bilangan bulat bertanda 16-bit

int - Bilangan bulat bertanda 32-bit

long - Bilangan bulat bertanda 64-bit

char - Karakter 16-bit (bilangan bulat tak bertanda)

Meskipun chartidak mendukung unsignedaritmatika, pada dasarnya dapat diperlakukan sebagai unsignedbilangan bulat. Anda harus secara eksplisit memasukkan operasi aritmatika kembali char, tetapi itu memberi Anda cara untuk menentukan unsignedangka.

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--;

Ya, tidak ada dukungan langsung untuk bilangan bulat tak bertanda (jelas, saya tidak perlu mengembalikan sebagian besar operasi saya ke char jika ada dukungan langsung). Namun, tentu saja ada tipe data primitif yang tidak ditandatangani. Saya ingin melihat byte yang tidak ditandatangani juga, tapi saya kira menggandakan biaya memori dan alih-alih menggunakan char adalah pilihan yang layak.


Edit

Dengan JDK8 ada API baru untuk Longdan Integeryang menyediakan metode pembantu saat memperlakukan longdan intnilai sebagai nilai yang tidak ditandatangani.

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

Selain itu, Guava menyediakan sejumlah metode pembantu untuk melakukan hal serupa pada tipe integer yang membantu menutup celah yang ditinggalkan oleh kurangnya dukungan asli untuk unsignedinteger.

Jyro117
sumber
2
Namun, charterlalu kecil untuk mendukung longaritmatika, misalnya.
3
Ini bisa menjadi kerugian dari Java
Berharap mereka mendukung nilai unsigned untuk byte. Membuat segalanya lebih mudah.
mixz
15

Java memang memiliki tipe unsigned, atau setidaknya satu: char adalah unsigned short. Jadi alasan apa pun yang dilontarkan Gosling, itu hanyalah ketidaktahuannya mengapa tidak ada tipe yang tidak ditandatangani.

Juga Tipe pendek: celana pendek digunakan sepanjang waktu untuk multimedia. Alasannya adalah Anda dapat memasukkan 2 sampel dalam 32-bit unsigned lama dan banyak vektorisasi banyak operasi. Hal yang sama dengan data 8-bit dan byte yang tidak ditandatangani. Anda dapat memasukkan 4 atau 8 sampel dalam register untuk vectorisasi.

menepuk
sumber
37
Ya, saya yakin Gosling sangat tidak tahu tentang Jawa jika dibandingkan dengan Anda.
jakeboxer
Apakah Java memungkinkan aritmatika dilakukan secara langsung pada jumlah byte yang tidak ditandatangani, atau apakah nilai selalu dipromosikan? Memiliki tipe unsigned untuk penyimpanan, tetapi selalu melakukan aritmatika pada tipe yang ditandatangani yang cukup besar untuk menampungnya berfungsi dengan baik secara semantik, tetapi akan menyebabkan operasi pada tipe unsigned yang ukurannya sama dengan bilangan bulat "normal" menjadi lebih mahal.
supercat
2
Ini gaya yang buruk untuk digunakan charselain karakter.
starblue
5
@ starblue Tentu saja, tapi ini peretasan untuk menyiasati keterbatasan bahasa
Dasar
14

Segera setelah int yang ditandatangani dan tidak ditandatangani dicampur dalam sebuah ekspresi, hal-hal mulai menjadi berantakan dan Anda mungkin akan kehilangan informasi. Membatasi Java ke ints yang ditandatangani hanya benar-benar membersihkan segalanya. Saya senang saya tidak perlu khawatir tentang seluruh bisnis yang ditandatangani / tidak ditandatangani, meskipun kadang-kadang saya ketinggalan bit ke-8 dalam byte.

Bombe
sumber
12
Mengenai pencampuran yang ditandatangani / tidak ditandatangani: Anda dapat memiliki jenis yang tidak ditandatangani, tetapi melarang pencampuran (atau memerlukan cetakan yang eksplisit). Namun, tidak jelas apakah itu perlu.
sleske
2
Dalam C ++ Anda harus memercikkan static_castbanyak untuk mencampurnya. Memang berantakan.
Raedwald
4
Bit ke-8 ada di sana, ia hanya mencoba menyembunyikan dirinya sebagai tandanya.
starblue
Hal-hal hanya menjadi berantakan dengan tipe 32 bit atau lebih besar. Saya tidak melihat alasan Jawa seharusnya byteditandatangani seperti di Pascal.
supercat
12
Ayo temui saya ketika Anda mengalami masalah dengan pemrosesan gambar di Jawa, di mana Anda berharap byte tidak ditandatangani. Maka Anda akan tahu bahwa & 0xFFsetiap promosi byte-ke-int membuat kode lebih berantakan.
bit2shift
12

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

Orang ini mengatakan karena standar C mendefinisikan operasi yang melibatkan int ditandatangani dan ditandatangani untuk diperlakukan sebagai unsigned. Ini dapat menyebabkan bilangan bulat bertanda negatif untuk berguling-guling ke int unsigned besar, berpotensi menyebabkan bug.

akatakritos
sumber
34
Bilangan bulat bertanda Java juga berputar. Saya tidak mengerti maksud Anda.
foo
8
@foo: Bilangan bulat yang ditandatangani harus menjadi besar sebelum menyebabkan masalah. Sebaliknya, dalam C, seseorang dapat memiliki masalah membandingkan bilangan bulat negatif - bahkan - untuk -1setiap quanity yang tidak ditandatangani - bahkan nol.
supercat
Sayang sekali Java tidak bisa memasukkan tipe yang tidak ditandatangani, tetapi dengan konversi terbatas dan operator campuran (agak analog dengan cara di C satu yang dapat menambahkan 5 ke sebuah pointer, tetapi orang tidak dapat membandingkan pointer ke 5) . Gagasan bahwa menggunakan operator pada tipe campuran ketika ada pemain implisit, harus memaksakan penggunaan implisit pemain itu (dan menggunakan jenis konsekuensi sebagai jenis hasil) terletak di jantung banyak keputusan desain yang meragukan di kedua .NET dan Jawa.
supercat
4
Bukan untuk mengomel atas jawaban Anda, tetapi memiliki -1usia "tidak diketahui" (seperti yang disarankan artikel) adalah salah satu contoh klasik "bau kode" . Misalnya, jika Anda ingin menghitung "berapa Alice lebih tua dari Bob?", Dan A = 25 dan B = -1, Anda akan mendapatkan jawaban ±26yang salah. Penanganan yang tepat dari nilai yang tidak diketahui adalah Option<TArg>kapan Some(25) - Noneakan kembali None.
bytebuster
11

Saya pikir Java baik-baik saja, menambahkan unsigned akan menyulitkannya tanpa banyak keuntungan. Bahkan dengan model integer yang disederhanakan, kebanyakan programmer Java tidak tahu bagaimana tipe numerik dasar berperilaku - cukup baca buku Java Puzzlers untuk melihat kesalahpahaman apa yang mungkin Anda miliki.

Adapun saran praktis:

  • Jika nilai Anda agak sewenang-wenang dan tidak cocok int, gunakan long. Jika tidak cocok longdigunakan BigInteger.

  • Gunakan tipe yang lebih kecil hanya untuk array ketika Anda perlu menghemat ruang.

  • Jika Anda membutuhkan tepat 64/32/16/8 bit, gunakan long/ int/ short/ bytedan berhentilah mengkhawatirkan tentang bit tanda, kecuali untuk pembagian, perbandingan, shift kanan, dan casting.

Lihat juga jawaban ini tentang "porting generator angka acak dari C ke Jawa".

starblue
sumber
5
Ya, untuk menggeser ke kanan Anda harus memilih antara >>dan >>>untuk yang ditandatangani dan yang tidak, masing-masing. Bergeser ke kiri tidak masalah.
starblue
1
@ starblue Sebenarnya >>>tidak berfungsi untuk shortdan byte. Misalnya, (byte)0xff>>>1hasilkan 0x7fffffffbukan 0x7f. Contoh lain: byte b=(byte)0xff; b>>>=1;akan menghasilkan b==(byte)0xff. Tentu saja Anda dapat melakukannya b=(byte)(b & 0xff >> 1);tetapi ini menambah satu operasi lagi (bitwise &).
CITBL
7
"... Bahkan dengan model yang disederhanakan kebanyakan programmer Java tidak tahu bagaimana tipe numerik dasar berperilaku ..." Sesuatu dalam diriku hanya membenci bahasa yang ditujukan pada penyebut umum terendah.
Dasar
Kalimat
Nayuki
1
@Nayuki Artikel Anda sangat bagus. Hanya sebuah komentar kecil, saya akan menggunakan penambahan 0x80000000 untuk operator perbandingan, bukan XOR, karena itu menjelaskan mengapa ia bekerja, itu menggeser wilayah yang berdekatan di mana perbandingan terjadi dari -MAXINT ke 0. Bitwise efeknya persis sama.
starblue
6

Dengan JDK8 itu memang memiliki beberapa dukungan untuk mereka.

Kita mungkin melihat dukungan penuh dari tipe yang tidak ditandatangani di Jawa terlepas dari kekhawatiran Gosling.

John Hascall
sumber
12
alias "Jadi orang benar-benar menggunakannya dan kami salah untuk tidak memasukkannya sebagai permulaan" - tapi kami masih belum cukup mempercayai pengembang Java untuk mengetahui apakah suatu variabel ditandatangani atau tidak - jadi kami tidak akan mengimplementasikannya di VM atau sebagai jenis yang setara dengan sepupu mereka yang ditandatangani.
Dasar
6

Saya tahu posting ini terlalu lama; namun untuk minat Anda, di Java 8 dan yang lebih baru, Anda dapat menggunakan inttipe data untuk mewakili integer 32-bit yang tidak ditandatangani, yang memiliki nilai minimum 0 dan nilai maksimum 2 32 −1. Gunakan Integerkelas untuk menggunakan inttipe data sebagai bilangan bulat yang tidak ditandai dan metode statis seperti compareUnsigned(), divideUnsigned()dll. Telah ditambahkan ke Integerkelas untuk mendukung operasi aritmatika untuk bilangan bulat yang tidak ditandai.

Morteza Adi
sumber
4

Saya pernah mendengar cerita bahwa mereka akan dimasukkan dekat dengan rilis Jawa orignal. Oak adalah pendahulu untuk Java, dan dalam beberapa dokumen spesifikasi disebutkan nilai-nilai usigned. Sayangnya ini tidak pernah berhasil masuk ke dalam bahasa Jawa. Sejauh siapa pun bisa mengetahui mereka hanya tidak diimplementasikan, kemungkinan karena kendala waktu.

Rob Ottaway
sumber
Ini akan baik-baik saja ... kecuali bukti dari wawancara Gosling menyiratkan bahwa bilangan bulat yang tidak ditandatangani (terpisah dari char) ditinggalkan karena para perancang pikir itu adalah ide yang buruk ... diberikan tujuan bahasa.
Stephen C
Adalah ide yang baik untuk tidak terlalu banyak memberi nilai pada pernyataan saksi mata, jika bukti dokumenter juga tersedia.
user7610
4

Saya pernah mengikuti kursus C ++ dengan seseorang di komite standar C ++ yang menyiratkan bahwa Java membuat keputusan yang tepat untuk menghindari bilangan bulat yang tidak ditandai karena (1) sebagian besar program yang menggunakan bilangan bulat yang tidak ditandatangani dapat dilakukan dengan baik dengan bilangan bulat yang ditandatangani dan ini lebih alami di dalam hal cara orang berpikir, dan (2) menggunakan bilangan bulat yang tidak ditandatangani menghasilkan banyak hal yang mudah dibuat tetapi sulit untuk men-debug masalah seperti bilangan bulat aritmatika bilangan bulat dan kehilangan bit signifikan ketika mengkonversi antara jenis yang ditandatangani dan yang tidak ditandatangani. Jika Anda salah mengurangi 1 dari 0 menggunakan bilangan bulat yang ditandatangani, sering kali program Anda lebih cepat macet dan membuatnya lebih mudah untuk menemukan bug daripada membungkusnya menjadi 2 ^ 32 - 1, dan kompiler serta alat analisis statis dan pemeriksaan runtime harus menganggap Anda tahu apa yang Anda lakukan karena Anda memilih untuk menggunakan aritmatika yang tidak ditandatangani. Juga,

Dulu, ketika memori terbatas dan prosesor tidak secara otomatis beroperasi pada 64 bit sekaligus, setiap bit menghitung lebih banyak, jadi setelah menandatangani vs unsigned byte atau celana pendek sebenarnya lebih penting dan jelas keputusan desain yang tepat. Saat ini hanya menggunakan int yang ditandatangani sudah lebih dari cukup di hampir semua kasus pemrograman reguler, dan jika program Anda benar-benar perlu menggunakan nilai yang lebih besar dari 2 ^ 31 - 1, Anda seringkali tetap menginginkan yang lama. Setelah Anda berada di wilayah penggunaan long, bahkan lebih sulit untuk menemukan alasan mengapa Anda benar-benar tidak dapat bertahan dengan 2 ^ 63 - 1 bilangan bulat positif. Setiap kali kita pergi ke prosesor 128 bit itu akan menjadi lebih sedikit masalah.

Jonathan
sumber
2

Pertanyaan Anda adalah "Mengapa Java tidak mendukung int yang tidak ditandatangani"?

Dan jawaban saya untuk pertanyaan Anda adalah bahwa Java ingin semua tipe primitifnya: byte , char , short , int dan long harus diperlakukan sebagai byte , word , dword dan qword , persis seperti dalam assembly, dan operator Java ditandatangani operasi pada semua itu tipe primitif kecuali untuk char , tetapi hanya pada char mereka tidak ditandatangani 16 bit saja.

Jadi metode statis seharusnya menjadi operasi yang tidak ditandatangani juga untuk 32 dan 64 bit.

Anda memerlukan kelas final, yang metode statisnya dapat dipanggil untuk operasi yang tidak ditandatangani .

Anda dapat membuat kelas akhir ini, sebut saja nama apa pun yang Anda inginkan dan terapkan metode statisnya.

Jika Anda tidak tahu cara menerapkan metode statis maka tautan ini dapat membantu Anda.

Menurut pendapat saya, Java tidak sama dengan C ++ sama sekali , jika tidak mendukung tipe yang tidak ditandatangani atau overloading operator, jadi saya pikir Java harus diperlakukan sebagai bahasa yang sama sekali berbeda dari C ++ dan dari C.

Ngomong-ngomong, bahasa ini juga sangat berbeda dalam hal bahasa.

Jadi saya tidak merekomendasikan di Java untuk mengetikkan kode yang mirip dengan C dan saya tidak merekomendasikan untuk mengetikkan kode yang mirip dengan C ++ sama sekali, karena di Jawa Anda tidak akan bisa melakukan apa yang ingin Anda lakukan selanjutnya di C ++, yaitu kode tidak akan terus menjadi C ++ sama sekali dan bagi saya ini buruk untuk kode seperti itu, untuk mengubah gaya di tengah.

Saya sarankan untuk menulis dan menggunakan metode statis juga untuk operasi yang ditandatangani, jadi Anda tidak melihat dalam campuran kode operator dan metode statis untuk operasi yang ditandatangani dan tidak ditandatangani, kecuali jika Anda hanya perlu menandatangani operasi dalam kode, dan tidak apa-apa untuk gunakan operator saja.

Juga saya sarankan untuk menghindari menggunakan pendek , int dan panjang tipe primitif, dan penggunaan kata , dword dan QWORD masing-masing sebagai gantinya, dan Anda tentang memanggil metode statis untuk operasi ditandatangani dan / atau menandatangani operasi daripada menggunakan operator.

Jika Anda akan melakukan operasi yang ditandatangani saja dan menggunakan operator hanya dalam kode, maka ini boleh saja untuk menggunakan tipe primitif ini pendek , int dan panjang .

Sebenarnya kata , dword dan QWORD jangan tidak ada dalam bahasa, tetapi Anda dapat membuat kelas baru untuk masing-masing dan pelaksanaan setiap harus sangat mudah:

Kelas kata memegang tipe primitif pendek saja, kelas dword memegang tipe primitif int saja dan kelas QWORD memegang jenis primitif panjang saja. Sekarang semua unsigned dan metode yang ditandatangani sebagai statis atau tidak sebagai pilihan Anda, Anda dapat menerapkan di setiap kelas, yaitu semua operasi 16 bit baik ditandatangani dan ditandatangani dengan memberikan nama makna pada kelas kata , semua operasi 32 bit baik unsigned dan ditandatangani dengan memberikan nama makna pada kelas kata sandi dan semua operasi 64 bit baik ditandatangani dan ditandatangani dengan memberikan nama makna pada kelas kata sandi .

Jika Anda tidak suka memberikan terlalu banyak nama yang berbeda untuk setiap metode, Anda selalu dapat menggunakan kelebihan beban di Jawa, bagus untuk membaca bahwa Java tidak menghapus itu juga!

Jika Anda menginginkan metode alih-alih operator untuk operasi bertanda tangan 8 bit dan metode untuk operasi tanpa tanda tangan 8 bit yang tidak memiliki operator sama sekali, maka Anda dapat membuat kelas Byte (perhatikan bahwa huruf pertama 'B' adalah modal, jadi ini bukan tipe byte primitif ) dan mengimplementasikan metode di kelas ini.

Tentang lewat nilai dan lewat referensi:

Jika saya tidak salah, seperti di C #, benda primitif yang disahkan oleh nilai alamiah, tetapi benda-benda kelas tersebut diteruskan oleh referensi secara alami, sehingga berarti bahwa objek tipe Byte , kata , dword dan QWORD akan dikirimkan dengan referensi dan bukan oleh nilai secara default. Saya berharap Java memiliki objek struct seperti yang dimiliki C #, jadi semua Byte , word , dword , dan qword dapat diimplementasikan menjadi struct, bukan kelas, jadi secara default mereka dilewatkan oleh nilai dan bukan oleh referensi secara default, seperti objek struct apa pun di C #, seperti tipe primitif, dilewatkan oleh nilai dan bukan oleh referensi secara default, tetapi karena Java lebih buruk daripada C # dan kami memiliki untuk mengatasinya, maka hanya ada kelas dan antarmuka, yang dilewatkan oleh referensi dan bukan oleh nilai secara default. Jadi, jika Anda ingin meneruskan objek Byte , word , dword , dan qword dengan nilai dan bukan dengan referensi, seperti objek kelas lainnya di Jawa dan juga dalam C #, Anda harus cukup menggunakan copy constructor dan hanya itu.

Itulah satu-satunya solusi yang dapat saya pikirkan. Saya hanya berharap bahwa saya bisa mengetikkan tipe primitif ke kata, kata dan qword, tetapi Java tidak mendukung typedef atau menggunakan sama sekali, tidak seperti C # yang mendukung penggunaan , yang setara dengan typedef C.

Tentang output:

Untuk urutan bit yang sama , Anda dapat mencetaknya dengan banyak cara: Sebagai biner, sebagai desimal (seperti arti% u dalam C printf), sebagai oktal (seperti arti% o dalam C printf), sebagai heksadesimal (seperti arti% x dalam printf C) dan sebagai integer (seperti arti dari% d dalam printf C).

Perhatikan bahwa C printf tidak tahu tipe variabel yang diteruskan sebagai parameter ke fungsi, jadi printf tahu tipe setiap variabel hanya dari objek char * yang diteruskan ke parameter pertama dari fungsi.

Jadi di masing-masing kelas: Byte , word , dword dan qword , Anda dapat menerapkan metode cetak dan mendapatkan fungsionalitas printf, meskipun tipe primitif dari kelas tersebut ditandatangani, Anda masih dapat mencetaknya sebagai unsigned dengan mengikuti beberapa algoritma yang melibatkan operasi logis dan bergeser untuk mendapatkan digit untuk mencetak ke output.

Sayangnya tautan yang saya berikan kepada Anda tidak menunjukkan cara menerapkan metode cetak ini, tetapi saya yakin Anda dapat google untuk algoritma yang Anda butuhkan untuk menerapkan metode cetak ini.

Hanya itu yang bisa saya jawab pertanyaan Anda dan sarankan Anda.


sumber
MASM (Microsoft assembler) dan Windows mendefinisikan BYTE, WORD, DWORD, QWORD, sebagai tipe yang tidak ditandatangani. Untuk MASM, SBYTE, SWORD, SDWORD, SQWORD adalah tipe yang ditandatangani.
rcgldr
1

Karena unsignedtipe adalah kejahatan murni.

Fakta bahwa dalam C unsigned - intmenghasilkan unsignedbahkan lebih jahat.

Ini adalah snapshot dari masalah yang membakar saya lebih dari sekali:

// 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 ...
}

Sudahkah Anda memperhatikan bug itu? Saya akui saya baru melihatnya setelah masuk dengan debugger.

Karena ntipe unsigned size_tseluruh ekspresi n - (rays.size() - 1) / 2dievaluasi sebagai unsigned. Ekspresi itu dimaksudkan untuk menjadi posisi yang ditandatangani dari nsinar th dari yang tengah: sinar ke-1 dari yang tengah di sisi kiri akan memiliki posisi -1, yang pertama di sebelah kanan akan memiliki posisi +1, dll. Setelah mengambil nilai abs dan mengalikannya dengan deltasudut saya akan mendapatkan sudut antara nsinar th dan yang tengah.

Sayangnya bagi saya ungkapan di atas mengandung kejahatan yang tidak ditandatangani dan alih-alih mengevaluasi, katakan, -1, ia mengevaluasi menjadi 2 ^ 32-1. Konversi berikutnya untuk doublemenutup bug.

Setelah satu atau dua bug yang disebabkan oleh penyalahgunaan unsignedaritmatika kita harus mulai bertanya-tanya apakah bit tambahan yang didapat sebanding dengan masalah ekstra. Saya berusaha, sedapat mungkin, untuk menghindari penggunaan unsignedtipe dalam aritmatika, meskipun masih menggunakannya untuk operasi non-aritmatika seperti topeng biner.

Michael
sumber
Menambahkan "unsigned long" ke Java akan terasa canggung. Namun, menambahkan tipe unsign yang lebih kecil seharusnya tidak menimbulkan masalah. Terutama jenis yang lebih kecil dari "int" dapat dengan mudah ditangani dengan meminta mereka mempromosikan ke "int" dengan cara yang jelas secara numerik, dan "int unsigned" bisa ditangani dengan mengatakan bahwa operasi yang melibatkan int yang ditandatangani dan int yang tidak ditandatangani akan mempromosikan keduanya operan ke "long". Satu-satunya situasi masalah adalah operasi yang melibatkan jumlah unsigned long dan jumlah yang ditandatangani, karena tidak akan ada tipe yang mampu mewakili semua nilai dari kedua operan.
supercat
@supercat: jika unsigneddikonversi ke intsetiap operasi, apa gunanya unsigned? Itu tidak akan memiliki fungsi yang dapat dibedakan dari short. Dan jika Anda mengonversi inthanya pada operasi campuran, seperti unsigned+intatau unsigned+float, maka Anda masih memiliki masalah ((unsigned)25-(unsigned)30)*1.0 > 0, yang merupakan penyebab utama unsignedbug terkait.
Michael
Banyak operasi pada tipe yang tidak ditandatangani akan dipromosikan ke "long". Membutuhkan gips yang eksplisit saat menyimpan hasil kembali ke tipe yang tidak ditandatangani akan menyebabkan gangguan yang sama seperti yang terjadi pada short dan byte, tetapi jika tipe tersebut terutama merupakan format penyimpanan daripada format perhitungan yang seharusnya tidak menjadi masalah. Dalam kasus apa pun, tipe yang tidak ditandatangani yang lebih pendek dari "int" seharusnya dapat dipromosikan menjadi "int" tanpa kesulitan.
supercat
3
Saya tidak suka jawaban ini karena menggunakan argumen "bilangan bulat bertanda adalah jahat dan tidak boleh ada karena mereka tidak pernah bisa ditandatangani". Siapa pun yang mencoba mengurangi dari bilangan bulat yang tidak ditandatangani harus sudah mengetahui hal ini. Dan untuk keterbacaan, C tidak dikenal karena mudah diikuti. Lebih jauh lagi, argumen (semi-) "bit ekstra tidak sepadan dengan masalah ekstra" juga sangat lemah. Apakah penanganan kesalahan bukannya exit(1);benar - benar 'sepadan dengan masalah ekstra'? Apakah tidak dapat membuka file besar benar-benar layak untuk keamanan yang programmer java kurang berpengalaman tidak akan mengacaukan menggunakan unsigned?
yyny
2
Satu-satunya hal jahat yang saya lihat dalam kode ini adalah n - (rays.size() - 1) / 2. Anda harus selalu memberi tanda kurung pada operator biner karena pembaca kode tidak perlu berasumsi tentang urutan operasi dalam program komputer. Hanya karena kami secara konvensional mengatakan a + b c = a + (b c) tidak berarti Anda dapat menganggap ini ketika membaca kode. Selanjutnya, perhitungan harus didefinisikan di luar loop sehingga dapat diuji tanpa loop hadir. Ini adalah bug karena tidak memastikan tipe Anda berbaris dan bukan masalah bilangan bulat yang tidak ditandatangani. Dalam C terserah Anda untuk memastikan jenis Anda berbaris.
Dmitry
0

Ada beberapa permata dalam spesifikasi 'C' yang dijatuhkan Java karena alasan pragmatis tetapi yang perlahan-lahan merayap kembali dengan permintaan pengembang (penutupan, dll).

Saya menyebutkan yang pertama karena terkait dengan diskusi ini; kepatuhan nilai pointer ke aritmatika integer tak bertanda. Dan, terkait dengan topik utas ini, sulitnya mempertahankan semantik yang tidak ditandatangani di dunia Jawa yang Ditandatangani.

Saya akan menebak jika seseorang mendapatkan alter ego Dennis Ritchie untuk memberi saran kepada tim desain Gosling, itu akan menyarankan memberi Signed sebuah "nol pada tak terbatas", sehingga semua permintaan penggantian alamat pertama-tama akan menambahkan ALGEBRAIC RING SIZE mereka untuk meniadakan nilai negatif.

Dengan begitu, setiap offset yang dilemparkan ke array tidak akan pernah menghasilkan SEGFAULT. Misalnya dalam kelas enkapsulasi yang saya sebut RingArray dari ganda yang membutuhkan perilaku tidak ditandatangani - dalam konteks "putaran otomatis":

// ...
// 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
// ...

RingArray di atas tidak akan pernah 'dapatkan' dari indeks negatif, bahkan jika pemohon jahat mencoba. Ingat, ada juga banyak permintaan sah untuk meminta nilai indeks sebelumnya (negatif).

NB:% luar modulus de-referensi permintaan yang sah sedangkan bagian dalam% modulus menutupi kebencian terang-terangan dari negatif lebih negatif daripada -modulus. Jika ini pernah muncul di Java + .. + 9 || 8 + .. + spec, maka masalahnya akan benar-benar menjadi 'programmer yang tidak bisa "memutar sendiri" KESALAHAN'.

Saya yakin apa yang disebut Java unsigned int 'defisiensi' dapat disesuaikan dengan one-liner di atas.

PS: Hanya untuk memberi konteks pada tata cara RingArray di atas, inilah operasi 'set' kandidat untuk mencocokkan operasi elemen 'get' di atas:

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
}
MKhomo
sumber
-2

Saya dapat memikirkan satu efek samping yang tidak menguntungkan. Dalam basis data tertanam java, jumlah id yang dapat Anda miliki dengan bidang id 32bit adalah 2 ^ 31, bukan 2 ^ 32 (~ 2billion, bukan ~ 4billion).

mike g
sumber
1
Dia mungkin berpikir tentang array dan tidak bisa menggunakan bilangan bulat negatif sebagai indeks. Mungkin.
SK9
2
Ketika bidang kenaikan-otomatis dalam basis data meluap, mereka sering menjadi aneh.
Joshua
-8

Alasan IMHO adalah karena mereka terlalu malas untuk mengimplementasikan / memperbaiki kesalahan itu. Menyarankan bahwa programmer C / C ++ tidak mengerti unsigned, struktur, union, bit flag ... Hanya tidak masuk akal.

Eter Anda sedang berbicara dengan programmer dasar / bash / java di ambang memulai pemrograman ala C, tanpa pengetahuan nyata bahasa ini atau Anda hanya berbicara keluar dari pikiran Anda sendiri. ;)

ketika Anda berurusan setiap hari dalam format baik dari file atau perangkat keras Anda mulai mempertanyakan, apa yang mereka pikirkan.

Contoh yang baik di sini adalah mencoba menggunakan byte yang tidak ditandai sebagai loop yang berputar sendiri. Bagi Anda yang tidak mengerti kalimat terakhir, bagaimana mungkin Anda menyebut diri Anda seorang programmer.

DC

Denis Co
sumber
34
Hanya untuk iseng, Google frase "loop berputar sendiri". Jelas , Denis Co adalah satu-satunya orang di dunia yang layak menyebut dirinya programmer :-)
Stephen C
6
Jawaban ini sangat buruk sehingga lucu
Nayuki