Javaがunsigned intをサポートしないのはなぜですか?


374

Javaに符号なし整数のサポートが含まれていないのはなぜですか?

予想外に大きな入力でオーバーフローが発生する可能性が低いコードを記述できることを考えると、私には奇妙な省略のようです。

さらに、符号なし整数を使用すると、unsigned intが保持することを意図していた値が負になることは決してないことが示されているため、自己文書化の一種になる可能性があります。

最後に、場合によっては、除算などの特定の演算では符号なし整数の方が効率的です。

これらを含めることの欠点は何ですか?


137
私にはわかりませんが、それは私の地獄を苛立たせます。たとえば、この方法でネットワークコードを記述することははるかに困難です。
Tamas Czinege 2009年

20
言語/データベース/ ...の世界に2つのタイプしかなかったらよかったのです:数値と文字列:)
Liao

5
ネットワークコードの記述はそれほど難しくありません。BTW InputStream.read()は、たとえば署名されたバイトではなく、署名されていないバイトを返すため、ネットワークの例は混乱したIMHOです。唯一の混乱は、符号付きの値を書き込むことと、符号なしの値を書き込むことは異なると想定していることです。つまり、バイトレベルで何が起こっているのか実際にわからない場合です。
Peter Lawrey、2008

19
@ZachSaw-言語デザイナーがその引用をしているのを見たとき、私もダブルテイクをしました。符号なし整数よりも簡単なものはありません。符号付き整数は複雑です。特に、トランジスタレベルでビットをいじる場合を考えます。そして、符号付き整数はどのようにシフトしますか?私は、Javaの設計者がブール論理を理解するという深刻な問題を抱えていると結論付けなければなりませんでした。
PP。

8
私にとってbyte、まっすぐな140グレーレベルを与えることができないが、正しい値を取得-116する必要のある画像を使用して画像処理を行うことは困難になり& 0xffます。
Matthieu

回答:


193

これは、シンプルさについてのGoslingなどへのインタビューからのものです。

ゴスリング:私が言語デザイナーとして、私は最近自分自身を数えていませんが、「シンプル」が本当に意味を持っていたのは、J。ランダム開発者が仕様を頭に抱くと期待できたからです。その定義によれば、たとえば、Javaはそうではありません。実際、これらの言語の多くは、誰もが実際に理解していない、多くのコーナーケースに陥っています。符号なしのC開発者をクイズすると、すぐに、ほとんどのC開発者が実際に符号なしで何が行われるか、符号なし算術が何であるかを理解していないことがわかります。そのようなことがCを複雑にしました。Javaの言語部分は、かなり単純だと思います。検索する必要があるライブラリ。


222
ここでは具体的な例を挙げてGoslingに反対する必要があります(CLRからも)。配列に符号付き整数の長さの値または符号なしの長さを与えると、さらに混乱するのは何ですか?配列が負の長さを持つことは不可能ですが、私たちのAPIはそれが可能であることを示しています。
JaredPar 2009年

18
Javaを単純にするという議論は、代替案が非常に面倒だったために最終的に言語に取り入れられたテンプレートの欠如によって、私たちを混乱に陥らせた理由の一部です。適切なクラスでunsigned intをサポートできると思いますが、プリムは必要ありません
Uri

59
配列のインデックスを負にすることができないためにJavaが符号なし整数を必要とする場合、配列のインデックスは配列のサイズを超えることができないため、サブレンジ(Pascal)も必要です。
ウェインコンラッド

81
さて、彼はちょうど符号なしの型を持たないことの利点を話しました。では、短所を数えてみましょう...
Moshe Revah

83
言語の単純さよりもコードの単純さを好みます。それが私がJavaを嫌う理由です。
Pijusn 2012

50

行間を読むと、ロジックは次のようなものだったと思います。

  • 一般に、Java設計者は、利用可能なデータ型のレパートリーを簡素化したいと考えていました
  • 日常的には、最も一般的なニーズは署名されたデータ型であると感じていました
  • 特定のアルゴリズムを実装するために、符号なし算術が必要になる場合がありますが、そのようなアルゴリズムを実装するプログラマの種類には、符号付きデータ型を使用して符号なし算術を「回避」する知識もあります。

ほとんどの場合、それは合理的な決定でした。おそらく、私は持っているでしょう:

  • この1つのデータ型に対して、バイトを符号なしにするか、少なくとも名前が異なる可能性のある、署名済み/署名なしの代替を提供しました(署名することで一貫性が向上しますが、いつ符号付きバイトが必要になるのでしょうか?)
  • 'short'を廃止(最後に16ビット符号付き算術を使用したのはいつですか?)

それでも、多少の手間がかかりますが、32ビットまでの符号なし値の演算は悪くありません。ほとんどの人は、符号なし64ビット除算や比較を必要としません。


2
私も符号なしバイトが欲しいですが、整数型間の完全な一貫性の利点は、符号なしバイトがもたらす利便性を上回ると思います。
アランムーア

64
「日常の目的では、最も一般的な必要性は署名されたデータ型であると感じていました」私のC ++コードでは、「ここで、なぜ署名されていない整数ではなく、ここで署名された整数を使用しているのですか?」と考えることがよくあります。私は「符号付き」は規則というよりは例外であると感じています(もちろん、ドメインによって異なりますが、正の整数が自然数と呼ばれる理由があります;-))。
Luc Touraille、2011年

15
署名されていないバイトの呼び出しに賛成して、バイトが署名されていると想定して(あるべきように)画像処理を行うとき、デバッグに何時間も費やしました。
Helin Wang、

7
どれほど頻繁shortに使用されているかに驚いているでしょう-defltate / gzip / inflateアルゴリズムは16ビットであり、それらはショートに大きく依存しています...または少なくともshort[][確かにそれらはネイティブですが、Java実装にはテラバイトのデータが含まれています]。後者(short[])はint[]、2倍のメモリとメモリを必要としないため、大きな利点があります。
bestss

8
特定のアプリケーションでは、ショーツを使用すると、それが真であると想定するよりもパフォーマンスが向上するかどうかを測定する必要があります。intではなくshortを操作するために必要な余分なジッグリリーポークリー(通常はプロセッサーが「使用するのが好きなタイプ」)は、実際には特定のアプリケーションのパフォーマンスに悪影響を及ぼす可能性があります。常にではありませんが、想定するのではなく、テストする必要があります。
Neil Coffey

19

これは古い質問で、パットはcharについて簡単に言及しましたが、これを今後検討する他の人のために、これについてさらに詳しく説明する必要があると思いました。Javaプリミティブ型をさらに詳しく見てみましょう。

byte -8ビット符号付き整数

short -16ビット符号付き整数

int -32ビット符号付き整数

long -64ビット符号付き整数

char -16ビット文字(符号なし整数)

算術charはサポートしていませんがunsigned、基本的にはunsigned整数として扱うことができます。算術演算を明示的ににキャストし直すchar必要がありますが、unsigned数値を指定する方法を提供します。

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

はい、符号なし整数の直接サポートはありません(明らかに、直接サポートがあったとしても、ほとんどの操作をcharにキャストし直す必要はありません)。ただし、符号なしのプリミティブデータ型は確かに存在します。符号なしバイトも見たかったのですが、メモリコストを2倍にして、代わりにcharを使用することは実行可能なオプションだと思います。


編集する

JDK8には、新しいAPIがLongあり、値を符号なしの値としてInteger扱うときにヘルパーメソッドを提供します。longint

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

さらに、Guavaは整数型に対して同様のことを行うための多数のヘルパーメソッドを提供します。これは、整数に対するネイティブサポートの欠如によって残されたギャップを埋めるのに役立ちunsignedます。


2
ただし、たとえば、算術演算charをサポートするには小さすぎlongます。

3
これは、Javaの欠点になる可能性があります

それらがバイトの符号なし値をサポートすることを願っています。物事をより簡単にします。
mixz

15

Javaには符号なしの型があり、少なくとも1つはあります。charは符号なしのshortです。したがって、Goslingがスローするどのような言い訳でも、他の符号なしの型がない理由は、実際には彼の無知にすぎません。

また、ショートタイプ:ショートパンツはマルチメディアで常に使用されます。その理由は、単一の32ビット符号なしlongに2つのサンプルを収め、多くの演算をベクトル化できるためです。8ビットデータと符号なしバイトについても同様です。ベクトル化のために、4つまたは8つのサンプルをレジスターに収めることができます。


37
ええ、ゴスリングはあなたに比べてJavaについて非常に無知だと思います。
jakeboxer 09/12/12

Javaは、符号なしバイト量で直接演算を実行できますか、それとも値が常に昇格されますか?ストレージ用の符号なしの型を持っていますが、常にそれを収容するのに十分な大きさの符号付きの型で算術を実行すると、意味的にうまくいきますが、「通常の」整数と同じサイズの符号なしの型での演算はより高価になります。
スーパーキャット2012

2
char文字以外に使うのは悪いスタイルです。
starblue

5
@starblueもちろんそうですが、言語の制限を回避するためのハックです
基本的な

14

符号付きの整数と符号なしの整数が式に混在するとすぐに、事態は乱雑になり始め、おそらく情報失うことになります。Javaを署名されたintに制限すると、本当に問題が解決するだけです。署名付き/署名なしのビジネス全体について心配する必要がないのは嬉しいですが、バイトの8番目のビットを見落とすこともあります。


12
符号付き/符号なしの混合について:符号なしの型を使用できますが、混合を許可しません(または明示的なキャストが必要です)。それでも、それが必要かどうかは不明です。
sleske 2009年

2
C ++では、static_castそれらを混合するためにsをたくさん散らす必要があります。それは確かに厄介です。
Raedwald、2011

4
8番目のビットはそこにあり、それは単に自分自身を記号として隠そうとします。
starblue

32ビット以上のタイプでは、物事は厄介になります。bytePascalのようにJava が署名されるべきではなかった理由はわかりません。
スーパーキャット2014

12
バイトが署名されていないことが予想されるJavaの画像処理で問題が発生した場合は、私に会いに来てください。次に、& 0xFFすべてのバイトから整数への昇格を行うと、コードがさらに面倒になることがわかります。
bit2shift

12

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

この男は、C標準がunsignedおよびsigned intを含む操作をunsignedとして処理するように定義しているためと述べています。これにより、負の符号付き整数が大きなunsigned intに転がり、バグが発生する可能性があります。


34
Javaの符号付き整数も循環します。あなたの意見はわかりません。
foo

8
@foo:符号付き整数は、問題が発生する前に大きくする必要があります。これとは対照的に、Cでは、負の整数で-1も(符号なしの値でも)ゼロでも比較できない場合があります。
スーパーキャット2012

Javaに符号なしの型を含めることができなかったのは残念ですが、変換と混合演算子のセットが制限されています(Cでポインタに5を追加できるが、ポインタを5と比較できない方法に多少似ています)。 。暗黙のキャストが存在する場合に混合型で演算子を使用すると、そのキャストを暗黙的に使用する必要がある(そして結果の型として結果の型を使用する)べきであるという考えは、.NETとJava。
スーパーキャット2013

4
あなたの答えに不満を言うことはありませんが、-1(記事が示唆するように)「不明な」年齢を持っていることは、「コードのにおい」の典型的な例の 1つです。たとえば、「アリスがボブよりどれだけ古いか」、およびA = 25とB = -1を計算する場合、その答え±26は単純に間違っています。不明な値の適切な処理はOption<TArg>Some(25) - Noneが戻るときの一種ですNone
バイトバスター2014

11

Javaはそのままでも問題ないと思いますが、署名なしを追加すると、あまり利益がなくても複雑になります。単純化された整数モデルを使用しても、ほとんどのJavaプログラマーは基本的な数値型がどのように動作するかを知りません。Javaパズルの本を読んで、どのような誤解があるかを確認してください。

実用的なアドバイスについては:

  • 値がやや任意のサイズで、に収まらない場合はint、を使用してくださいlong。それらがlong使用に適合しない場合BigInteger

  • スペースを節約する必要がある場合は、配列にのみ小さいタイプを使用してください。

  • 正確に64/32/16/8ビットが必要な場合は、long/ int/ short/ byteを使用し、除算、比較、右シフト、およびキャストを除いて、符号ビットの心配をやめます。

「CからJavaへの乱数ジェネレーターの移植」に関するこの回答も参照してください。


5
はい、右にシフトするには、署名付きと署名なしをそれぞれ選択する必要が>>あります>>>。左にシフトしても問題ありません。
starblue

1
@starblue実際に>>>は機能しませんshortbyte。たとえば、ではなく(byte)0xff>>>1利回り。別の例:結果はになります。もちろんできますが、これによりもう1つの操作が追加されます(ビットごとの&)。0x7fffffff0x7fbyte b=(byte)0xff; b>>>=1;b==(byte)0xffb=(byte)(b & 0xff >> 1);
CITBL 2013年

7
「...単純化されたモデルでさえ、ほとんどのJavaプログラマーは基本的な数値型がどのように振る舞うかを知らない...」私の中の何かは、最も低い共通の分母を目指した言語に憤慨しています。
基本的な

より多くの合併症と少しゲインについてのあなたの答えの開口部のラインは、私は6年後の私の記事での詳述まさにです:nayuki.io/page/unsigned-int-considered-harmful-for-java
Nayuki

1
@Nayukiあなたの記事は本当にいいです。ほんの少しだけ、私はXORの代わりに比較演算子に0x80000000の追加を使用します。これは、それが機能する理由を説明するため、比較が発生する連続領域を-MAXINTから0にシフトします。ビットごとの効果はまったく同じです。
-starblue

6

JDK8それは彼らのためにいくつかのサポートを持っています。

Goslingの懸念にもかかわらず、Javaでは未署名の型が完全にサポートされる可能性があります。


12
別名「だから、人々は本当にそれを使用しており、最初にそれを含めないのは間違っていました」-しかし、Java開発者が変数が署名されているかどうかを知るのはまだ信頼できません-そのため、実装しませんVM内、または署名されたいとこと同等のタイプとして。
基本的な

6

私はこの投稿が古すぎることを知っています。ただし、Java 8以降では、intデータ型を使用して符号なし32ビット整数を表すことができます。これは、最小値が0、最大値が2 32 -1です。使用Integer用途にクラスint符号なし整数などの静的メソッドのようなデータ型をcompareUnsigned()divideUnsigned()等に追加されたInteger符号なし整数の算術演算をサポートするクラス。


4

最初のJavaリリースのすぐ近くに含まれるという話を聞いたことがあります。オークはJavaの前身であり、一部の仕様書では、悪意のある値について言及されていました。残念ながら、これらは決してJava言語にはなりませんでした。おそらく時間の制約が原因で、実装されなかったことが誰かにわかった限りです。


これは大丈夫です...ゴスリングのインタビューからの証拠charが、デザイナーがそれらを悪い考えだと思ったので符号なしの整数(を除いて)が除外されたことを示唆していることを除いて... 言語の目標を考えると...
スティーブンC

証拠書類が手元にある場合は、目撃証言にあまり価値を置かないことをお勧めします。
user7610 2018

4

(1)符号なし整数を使用するほとんどのプログラムは符号付き整数と同じように使用でき、これは(2)符号なし整数を使用すると、作成が非常に簡単になりますが、整数演算のオーバーフローや、符号付きと符号なしの型間の変換時に重要なビットが失われるなどのデバッグが困難になります。符号付き整数を使用して誤って0から1を減算すると、多くの場合、プログラムがクラッシュし、2 ^ 32-1に回り込むよりもバグを見つけやすくなります。コンパイラと静的分析ツール、およびランタイムチェックでは、符号なし演算を使用することを選択したので、何をしているのかを知っていると仮定します。また、

ずっと前に、メモリが限られていて、プロセッサが64ビットで一度に自動的に動作しなかったとき、すべてのビットがより多くを数えるので、実際に署名されたバイトと署名されていないバイトまたはショーツのほうがはるかに重要であり、明らかに正しい設計決定でした。今日、ほとんどすべての通常のプログラミングの場合、signed intを使用するだけで十分です。プログラムで実際に2 ^ 31-1より大きい値を使用する必要がある場合は、とにかく長い時間が必要です。longを使用する領域に入ると、2 ^ 63-1の正の整数で本当に満足できない理由を考え出すのはさらに難しくなります。128ビットプロセッサに移行すると、問題はさらに少なくなります。


2

あなたの質問は「なぜJavaはunsigned intをサポートしないのか」ということです。

そしてあなたの質問への私の答えは、Javaがそのプリミティブ型のすべてを望んでいるということです:bytecharshortint、およびlongは、アセンブリとまったく同じように、それぞれ、byteworddword、およびqwordとして扱われるべきであり、Java演算子は署名されていますそれのすべての操作が以外のプリミティブ型だ文字を、だけで文字彼らは、16ビットの符号なしのみです。

そう静的メソッドがあると仮定し、符号なしの動作、32ビットおよび64ビットのため。

署名されていない操作のために静的メソッドを呼び出すことができる最終クラスが必要です。

この最終クラスを作成し、好きな名前を付けて、静的メソッドを実装できます。

静的メソッドの実装方法がわからない場合は、このリンクが役立つ場合があります。

私の意見では、JavaはC ++ にまったく似ていません。Javaが符号なしの型演算子のオーバーロードサポートしていない場合、JavaはC ++とCの両方から完全に異なる言語として扱う必要があると思います。

ちなみに言語名も全然違います。

したがって、JavaでCと同様のコードを入力することはお勧めしません。また、C ++と同様のコードを入力することもお勧めしません。Javaでは、次にC ++で実行したいことを実行できないためです。つまり、コードはC ++のようにまったく機能しなくなり、私にとっては、途中でスタイルを変更するために、そのようなコードを作成することはできません。

署名付きの操作にも静的メソッドを作成して使用することをお勧めします。コードで署名付きの操作のみが必要で、それが演算子のみを使用してください。

また、shortint、およびlongプリミティブ型の使用を避け、代わりにworddword、およびqwordをそれぞれ使用することをお勧めします。演算子を使用する代わりに、符号なし演算および/または符号付き演算の静的メソッドを呼び出します。

符号付き操作のみを行い、コード内でのみ演算子を使用する場合は、これらのプリミティブ型shortint、およびlongを使用しても問題ありません。

実際にはworddwordqwordは言語に存在しませが、それぞれに対して新しいクラスを作成でき、それぞれの実装は非常に簡単です。

クラスwordはプリミティブ型shortのみを保持し、クラスdwordはプリミティブ型intのみを保持し、クラスqwordはプリミティブ型longのみを保持します。これで、すべての符号なしメソッドと符号付きメソッドを静的または非選択として、各クラスに実装できます。つまり、ワードクラスに意味のある名前を付けることにより、符号なしと符号付きのすべての16ビット演算、符号なしと符号付きの両方の32ビット演算すべて上の意味の名前を与えることによって署名DWORDクラスと符号なしと上の名前の意味を与えることにより、署名の両方のすべての64ビット演算QWORDクラスを。

あなたは、各メソッドのためにあまりにも多くの異なる名前を与えて気に入らない場合は、常にJavaがなかったことを読み取ることが、Javaでのオーバーロードの良いを使用することができない、あまりにもそれを取り除きます!

8ビットの符号付き演算の演算子ではなくメソッド、および演算子がまったくない8ビットの符号なし演算のメソッドが必要な場合は、Byteクラスを作成できます(最初の文字「B」が大文字であるため、これはプリミティブ型byte)とこのクラスのメソッドを実装します。

値渡しと参照渡しについて:

私が間違っていない場合、C#のように、プリミティブオブジェクトは値によって自然に渡されますが、クラスオブジェクトは自然に参照によって渡されるため、タイプByteworddword、およびqwordのオブジェクトは、値ではなく参照によって渡されますデフォルトでは。JavaにC#のように構造体オブジェクトがあったらいいので、すべてのByteworddwordqwordを実装して、クラスの代わりに構造体にすることができますなので、デフォルトでは、プリミティブ型のようなC#の構造体オブジェクトのように、デフォルトでは参照ではなく値で渡されましたが、デフォルトでは参照ではなく値で渡されますが、そのJavaはC#よりも悪いため、それを処理するために、デフォルトでは値ではなく参照によって渡されるクラスとインターフェースのみがあります。したがって、JavaやC#の他のクラスオブジェクトと同様に、参照ではなく値でByteworddword、およびqwordオブジェクトを渡す場合は、コピーコンストラクターを使用するだけでよいのです。

それが私が考えられる唯一の解決策です。基本型をword、dword、qwordにtypedefできればいいのですが、Javaはtypedefもまったく使用しません。Cのtypedefに相当するusingをサポートするC#とは異なります。

出力について:

同じビットシーケンスの場合、さまざまな方法でそれらを印刷できます。2進数、10進数(C printfでの%uの意味など)、8進数(C printfでの%oの意味など)、16進数(などC printfでの%xの意味)および整数として(C printfでの%dの意味と同様)。

Cのprintfは関数にパラメーターとして渡される変数の型を認識しないため、関数の最初のパラメーターに渡されるchar *オブジェクトからのみ、printfは各変数の型を認識します。

したがって、Byteworddword、およびqwordの各クラスでは、クラスのプリミティブ型が署名されていても、printメソッドを実装してprintfの機能を取得できます。数字を出力に出力するための論理演算とシフト演算。

残念ながら、私があなたに与えたリンクはこれらの印刷方法を実装する方法を示していませんが、これらの印刷方法を実装するために必要なアルゴリズムをググることができると私は確信しています。

それが私があなたの質問に答えてあなたに提案できるすべてです。


MASM(Microsoftアセンブラー)とWindowsでは、BYTE、WORD、DWORD、QWORDが符号なしの型として定義されています。MASMの場合、SBYTE、SWORD、SDWORD、SQWORDが署名されたタイプです。
rcgldr

1

ので、unsignedタイプが純粋な悪です。

Cでunsigned - int生成するという事実unsignedはさらに悪です。

以下は、私を何度も焼いた問題のスナップショットです。

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

バグに気づきましたか?私は、デバッガーを使用してステップインした後でのみ、それを確認しました。

そのためn、符号なし型であるsize_t全体の表現n - (rays.size() - 1) / 2として評価しますunsigned。その式は、真ん中の1番目の光線の符号付き位置になることを意図しています。n左側の真ん中の1番目の光線は位置-1になり、右側の1番目の光線は位置+1になります。 abs値を取り、delta角度を掛けるnと、光線と中央の光線の間の角度が得られます。

残念ながら、上記の式には符号なしの悪が含まれており、たとえば-1と評価する代わりに、2 ^ 32-1と評価されていました。doubleバグを封印するためのその後の変換。

unsigned算術演算の誤用によって引き起こされた1 つか2つのバグの後、1つ追加のビットが追加のトラブルに値するかどうか疑問に思う必要があります。可能な限り、unsigned算術で型を使用しないようにしますが、バイナリマスクなどの非算術演算には使用します。


「unsigned long」をJavaに追加するのは厄介です。ただし、より小さな符号なしの型を追加しても問題はありません。特に「int」よりも小さい型は、数値的に明白な方法で「int」に昇格させることで簡単に処理でき、「unsigned int」は、signed intとunsigned intを含む操作で昇格すると処理できます両方のオペランドを "long"にします。両方のオペランドのすべての値を表すことができる型がないため、唯一の問題状況は、unsigned longとsignedの数量を伴う演算です。
スーパーキャット2016

@supercat:すべての操作でunsignedに変換さintれた場合、どのように使用されunsignedますか?と区別できる機能はありませんshort。また、またはintなどの混合操作でのみに変換した場合でも、に関連するバグの主な原因であるの問題が発生します。unsigned+intunsigned+float((unsigned)25-(unsigned)30)*1.0 > 0unsigned
マイケル

符号なしの型に対する多くの操作は、 "long"に昇格します。結果を符号なしの型に格納するときに明示的なキャストを要求すると、short型やbyte型と同じように煩わしくなりますが、型が計算形式ではなく主に格納形式である場合は問題になりません。いずれの場合でも、「int」よりも短い符号なしの型は、問題なく「int」に昇格できるはずです。
スーパーキャット2016

3
「符号なし整数は悪であり、署名できないため存在しない」という引数を使用しているため、この回答は嫌いです。符号なし整数から減算しようとする人は、これをすでに知っているはずです。また、読みやすさに関しては、Cはわかりやすいことで正確に知られていません。さらに、(追加のビットは追加のトラブルに値しない)(半)引数も非常に弱いです。エラー処理はexit(1);本当に「追加のトラブルに値する」のではなくですか?経験の浅いJavaプログラマーが台無しにしないセキュリティの価値がある大きなファイルを開くことができないのunsignedですか?
yyny

2
このコードで私が目にする唯一の邪悪なものは n - (rays.size() - 1) / 2です。コードの読み取り側は、コンピュータープログラムでの操作の順序について何も想定する必要がないため、常に二項演算子を括弧で囲む必要があります。従来、a + b c = a +(b c)と言っているからといって、コードを読み取るときにこれを想定できるわけではありません。さらに、ループがなくてもテストできるように、計算はループの外で定義する必要があります。これは、符号なし整数の問題ではなく、型が揃っていないことを確認する際のバグです。Cでは、型が揃うようにするのはあなた次第です。
Dmitry

0

'C'仕様には、実用的な理由でJavaがドロップしたいくつかの宝石がありますが、開発者の要求(クロージャーなど)によって徐々に忍び寄っています。

それがこの議論に関連しているので、私は最初のものに言及します。ポインタ値の符号なし整数演算への準拠。そして、このスレッドのトピックに関連して、Javaの署名された世界で署名されていないセマンティクスを維持することの難しさ。

ゴスリングの設計チームにアドバイスするためにデニスリッチーの代替エゴを手に入れたら、Signedに「無限大のゼロ」を与えることを提案し、すべてのアドレスオフセットリクエストが最初にALGEBRAIC RING SIZEを追加して負の値を取り除くようにしたと思います。

このようにして、アレイでスローされたオフセットがSEGFAULTを生成することはありません。たとえば、私が符号なしの動作を必要とするdoubleのRingArrayを呼び出すカプセル化されたクラスでは、「自己回転ループ」のコンテキストで:

// ...
// 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は、悪意のあるリクエスタが試行した場合でも、負のインデックスから「取得」することは決してありません。以前の(負の)インデックス値を要求する正当な要求も多数あることに注意してください。

注意:外側の%modulusは正当なリクエストを逆参照しますが、内側の%modulusは露骨な悪意を-modulusよりも否定的なものから隠します。これがJavaで表示される場合+ .. + 9 || 8 + .. +仕様の場合、問題は本当に「障害を「自己回転」できないプログラマー」になるでしょう。

いわゆるJava unsigned intの「欠陥」は、上記のワンライナーで埋め合わせることができると確信しています。

PS:上記のRingArrayハウスキーピングにコンテキストを提供するためだけに、上記の「get」要素操作に一致する「set」操作の候補を次に示します。

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

残念な副作用が1つ考えられます。Java組み込みデータベースでは、32ビットのIDフィールドで使用できるIDの数は2 ^ 32ではなく2 ^ 31です(〜40億ではなく〜20億)。


1
彼はおそらく配列について考えており、負の整数をインデックスとして使用することはできません。多分。
SK9 '19年

2
データベースの自動インクリメントフィールドがオーバーフローすると、それらはしばしば奇妙なものになります。
ジョシュア

-8

私見の理由は、彼らがその間違いを実装/修正するのが面倒だからです。C / C ++プログラマーが符号なし、構造体、共用体、ビットフラグを理解していないことを示唆しています...

C言語のプログラミングを開始する寸前に、basic / bash / javaプログラマーと話していたEtherで、この言語についての知識がまったくないか、自分の頭から話しているだけです。;)

ファイルまたはハードウェアのいずれかからフォーマットを毎日取り扱っている場合、彼らは何を考えていたのでしょうか。

ここでの良い例は、自己回転ループとして符号なしバイトを使用することです。最後の文を理解していないあなたのために、一体全体であなたは自分をプログラマーと呼びます。

DC


34
キックのためだけに、Googleのフレーズ「自己回転ループ」。 明らかに、Denis Coは自分自身をプログラマーと呼ぶに値する世界で唯一の人物です:-)
Stephen C

6
この答えは非常に悪いのでおかしいです
ナユキ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.