Javaで符号なしバイトを作成できますか


185

符号付きバイトを符号なしに変換しようとしています。問題は、受信しているデータが符号なしであり、Javaが符号なしバイトをサポートしていないため、データを読み取るときに、そのデータを符号付きとして処理することです。

Stack Overflowから入手した次の解決策で変換してみました。

public static int unsignedToBytes(byte a)
{
    int b = a & 0xFF;
    return b;
}

しかし、再びバイトに変換すると、同じ署名データが得られます。このデータを、バイトのみをパラメーターとして受け入れるJavaの関数へのパラメーターとして使用しようとしているため、他のデータ型は使用できません。この問題を解決するにはどうすればよいですか?


2
グアバ:UnsignedBytes.toint(byte value)
jacktrades

20
java.lang.Byte.toUnsignedInt(byte value);
themarketka

回答:


107

私はあなたの質問を理解しているのかわかりません。

私はこれを試してみましたが、バイト-12(符号付きの値)の場合、整数244(符号なしバイトの値と同等ですが、として入力されます)を返しましたint

  public static int unsignedToBytes(byte b) {
    return b & 0xFF;
  }

  public static void main(String[] args) {
    System.out.println(unsignedToBytes((byte) -12));
  }

やりたいことですか?

Javaはbyte、Cのように244を値として表現することを許可していません。Byte.MAX_VALUE(127)を超える正の整数を表現するにはshortintやなどの他の整数型を使用する必要がありlongます。


1
byte b = (byte)unsignedToBytes((byte) -12); 今すぐbを印刷してみてください
Jigar Joshi 2010

101
なぜこれを正しい答えとして受け入れたのですか?それがするすべてはあなたがあなたの質問で言及する方法とまったく同じです-バイトを符号なし整数に変換します。
Adamski

1
時々署名された値、時には署名されていないことが重要なので、おそらくこれが彼がこの答えを受け入れた理由です。(byte)(b&0xff)は意味がありませんが、(byte)(Math.min((b&0xff)* 2、255))は意味があります。たとえば、コンピュータグラフィックスでは、pixedはバイトは2倍明るくなります。:-)
iirekm 2010年

3
それはあまりにもbyteToUnsigned呼び出される可能性
エルナンEche

195

プリミティブがJavaで署名されているという事実は、プリミティブがメモリ/トランジットでどのように表現されるかとは無関係です。1バイトは8ビットにすぎず、署名付き範囲として解釈するかどうかはあなた次第です。「this is signed」または「this is unsigned」を示す魔法の旗はありません。

プリミティブが署名されているため、Javaコンパイラーはバイトに+127より高い(または-128より低い)値を割り当てることを禁止します。ただし、これを達成するためにint(またはshort)をダウンキャストするのを止めることは何もありません。

int i = 200; // 0000 0000 0000 0000 0000 0000 1100 1000 (200)
byte b = (byte) 200; // 1100 1000 (-56 by Java specification, 200 by convention)

/*
 * Will print a negative int -56 because upcasting byte to int does
 * so called "sign extension" which yields those bits:
 * 1111 1111 1111 1111 1111 1111 1100 1000 (-56)
 *
 * But you could still choose to interpret this as +200.
 */
System.out.println(b); // "-56"

/*
 * Will print a positive int 200 because bitwise AND with 0xFF will
 * zero all the 24 most significant bits that:
 * a) were added during upcasting to int which took place silently
 *    just before evaluating the bitwise AND operator.
 *    So the `b & 0xFF` is equivalent with `((int) b) & 0xFF`.
 * b) were set to 1s because of "sign extension" during the upcasting
 *
 * 1111 1111 1111 1111 1111 1111 1100 1000 (the int)
 * &
 * 0000 0000 0000 0000 0000 0000 1111 1111 (the 0xFF)
 * =======================================
 * 0000 0000 0000 0000 0000 0000 1100 1000 (200)
 */
System.out.println(b & 0xFF); // "200"

/*
 * You would typically do this *within* the method that expected an 
 * unsigned byte and the advantage is you apply `0xFF` only once
 * and than you use the `unsignedByte` variable in all your bitwise
 * operations.
 *
 * You could use any integer type longer than `byte` for the `unsignedByte` variable,
 * i.e. `short`, `int`, `long` and even `char`, but during bitwise operations
 * it would get casted to `int` anyway.
 */
void printUnsignedByte(byte b) {
    int unsignedByte = b & 0xFF;
    System.out.println(unsignedByte); // "200"
}

5
多くの操作では違いはありませんが、一部の操作では違いがあります。いずれかの方法で、バイトを符号なしとして使用するか、または符号なしのcharを使用できます。
Peter Lawrey、2010年

62
潜在的に負の数の配列にアクセスしても問題はありません。
ステファン

3
@Stefan-私は、それらがネットワーク上でどのように表現されるかという文脈では無関係であることを意味しました。
アダムスキー

6
これは、質問にはやや無関係です。彼はそれをバイトパラメータのみを受け入れる関数に渡す必要があると述べたので、それをユニコーンのバイト表現として解釈することは天候に関係ありません。Javaは常にそれを符号付き数として扱います。これは、この関数がパラメーターをインデックスとして使用する場合の例では問題になる可能性があります。ただし、公平を期すために、他の上位2つの回答にも反対票を投じました。
Stefan

2
@Stefan +1。バイトを使用して256要素の配列にアクセスする場合は、絶対に関係があります。これは、JavaまたはC#に移行する前に、誰もがCおよびC ++の学習を開始する必要がある理由を示す優れた例です
Gianluca Ghettini

46

Javaで符号なしバイトを操作するための完全なガイド:

Javaの符号なしバイト

(この回答の出典。)


Java言語は、unsignedキーワードのようなものを提供しません。A byte場合、例えば127 -言語仕様に応じては、-128の間の値を表しているbyteにキャストされintたJava符号及び使用、第1のビットを解釈する符号拡張

とはいえ、byte単に8ビットとして表示して、それらのビットを0〜255の値として解釈することを妨げるものは何もありません。他の誰かの方法に解釈を強制する方法はないことに注意してください。メソッドがを受け入れる場合、byteそのメソッドは、特に明記されていない限り、-128〜127の値を受け入れます。

以下に、便利な変換/操作をいくつか示します。

intとの変換

// From int to unsigned byte
int i = 200;                    // some value between 0 and 255
byte b = (byte) i;              // 8 bits representing that value

// From unsigned byte to int
byte b = 123;                   // 8 bits representing a value between 0 and 255
int i = b & 0xFF;               // an int representing the same value

(または、Java 8以降を使用している場合は、を使用してくださいByte.toUnsignedInt。)

解析/フォーマット

最善の方法は、上記の変換を使用することです。

// Parse an unsigned byte
byte b = (byte) Integer.parseInt("200");

// Print an unsigned byte
System.out.println("Value of my unsigned byte: " + (b & 0xFF));

算数

2補数表現は、加算、減算、および乗算に対して「機能する」だけです。

// two unsigned bytes
byte b1 = (byte) 200;
byte b2 = (byte) 15;

byte sum  = (byte) (b1 + b2);  // 215
byte diff = (byte) (b1 - b2);  // 185
byte prod = (byte) (b2 * b2);  // 225

除算には、オペランドの手動変換が必要です。

byte ratio = (byte) ((b1 & 0xFF) / (b2 & 0xFF));

1
「char」は数値を表しません。
ログオフ

26
簡単に言えば、あなたは間違っています。
aioobe 2012

36

Javaにはプリミティブな符号なしバイトはありません。通常は、より大きな型にキャストします。

int anUnsignedByte = (int) aSignedByte & 0xff;

intへのキャストは必要ですか?
ニッチ2018

暗黙的なキャストでもかまいませんが、どちらの方法でもキャストできます。そして、そのキャストは署名付き拡張を行います。そしてそれは問題です。明示的なキャストを行うと、少なくともこれが起こっていることがわかります。
foo


4

余談ですが、印刷したい場合は、

byte b = 255;
System.out.println((b < 0 ? 256 + b : b));

6
なぜそんなに複雑なのですか?println(b & 0xff)十分です
phuclv


0

Adamskiが最良の回答を提供しましたが、完全ではありません。詳細については説明していませんので、彼の回答を読んでください。

符号なしバイトを渡す必要があるシステム関数がある場合は、自動的に符号なしバイトとして扱われるため、符号付きバイトを渡すことができます。

したがって、システム関数が4バイトを必要とする場合、たとえば、符号なしバイトとして192 168 0 1を渡すと、-64 -88 0 1を渡すことができます。関数に関数を渡す動作は、それらに署名しないため、関数は引き続き機能します。 。

ただし、クロスプラットフォーム互換性のためにシステム関数がクラスの背後に隠されているため、この問題が発生することはほとんどありません。ただし、java.ioのreadメソッドの一部は、unsighedバイトをintとして返します。

この動作を確認したい場合は、ファイルに符号付きバイトを書き込んで、符号なしバイトとして読み戻してください。


1
符号付きまたは符号なしバイトなどはありません。
VlastimilOvčáčík2015

あなたの例ではどのくらい正確にバイトを読み書きしましたか?
VlastimilOvčáčík15年

0

あなたもすることができます:

public static int unsignedToBytes(byte a)
{
    return (int) ( ( a << 24) >>> 24);
}    

説明:

まあ言ってみれば a = (byte) 133;

メモリには次のように保存されます: "1000 0101"(16進数で0x85)

したがって、その表現は、 符号なし = 133、符号付き = -123(2の補数として)に変換されます。

<< 24

左シフトを24ビット左に実行すると、結果はは次のように表される4バイト整数になります。

"10000101 00000000 00000000 00000000"(または16進数で "0x85000000")

その後、私たちは持っています

(a << 24)>>> 24

そして、再び右に24ビットシフトしますが、先行ゼロで埋められます。したがって、結果は次のようになります。

"00000000 00000000 00000000 10000101"(または16進数の "0x00000085")

そしてそれは133に等しい符号なし表現です。

キャストしようとするとa = (int) a; 、2の補数表現のバイトが保持され、intとしても2の補数として格納されます。

(int) "10000101" ---> "11111111 11111111 11111111 10000101"

そして、それは次のように変換されます:-123


2
2019では、これは不要です。だけを使用してくださいjava.lang.Byte.toUnsignedInt(byte value)。また、Java 8をまだ使用していない場合は、できるだけ早くアップグレードしてください。Java 7以前はサポートが終了しています。
スティーブンC

0

このデータを、パラメーターとしてバイトのみを受け入れるJavaの関数へのパラメーターとして使用しようとしています

これは、2 ^ 32-1より大きい値を渡したい整数を受け入れる関数と実質的に違いはありません。

それは関数がどのように定義され、文書化されるかに依存するように思えます。私は3つの可能性を見ることができます:

  1. 関数がバイトを符号なしの値として扱うことを明示的に文書化する場合があります。その場合、関数はおそらく期待どおりの動作をするはずですが、正しく実装されていないようです。整数の場合、関数はおそらくパラメータを符号なし整数として宣言しますが、バイトの場合は不可能です。

  2. この引数の値はゼロよりも大きい(またはおそらく等しい)必要があることが記載されている場合があります。その場合、関数の誤用(範囲外のパラメーターの受け渡し)が行われ、意図した以上の機能が期待されます。行う。ある程度のデバッグサポートがあれば、関数が例外をスローしたり、アサーションに失敗したりする可能性があります。

  3. ドキュメントには何も書かれていない場合があります。その場合、負のパラメーターは負のパラメーターであり、それが何らかの意味を持つかどうかは、関数の動作によって異なります。これが無意味である場合、おそらく関数は本当に(2)として定義/文書化されているはずです。これが明白でない方法で意味がある場合(たとえば、非負の値が配列のインデックス付けに使用され、負の値が配列の最後からのインデックス付けに使用されるため、-1は最後の要素を意味します)、ドキュメントはそれを言う必要がありますという意味で、とにかくそれがあなたがしたいことではないと思います。


うーん、私はバイトの符号についての別の質問を意図した返信を投稿したと思いますが、ここでも少し関連があると思います...
Kevin Martin

-1

符号付きバイトを渡す必要がある関数がある場合、符号なしバイトを渡すとどうなりますか?

なぜ他のデータ型を使用できないのですか?

通常は、バイトを符号なしバイトとして使用して、単純な変換または変換なしで使用できます。それはすべてそれがどのように使用されるかに依存します。あなたはそれで何をするつもりなのかを明確にする必要があります。


-1

Javaが言語に符号なしバイトを含まなかったのは(Cから来て)煩わしいように見えるかもしれませんが、単純な "b&0xFF"操作が(まれに)実際に必要な状況。ビットは実際には変化せず、解釈のみです(これは、たとえば値に対していくつかの数学演算を行う場合にのみ重要です)。


他の人の答えを見て、あなたの答えが最善/役立つと思いますか?少し説明してコメントに追加
Jubin Patel

8
あなたがそれに遭遇しなかったからといって、それは珍しいことではありません。プロトコルを実装してみると、100万回遭遇するでしょう。厄介なことは、私が遭遇したユースケースの大部分がバイトを扱う場合、符号なしバイトを扱うことです(それらは数値ではなくバイトであるため)。奇妙なことに、ビット演算はそれをintに変換します。つまり、「負」の値は、拡張すると完全に異なる値になります。はい、常にマスキングすることで回避できますが、時間とプロセッサの浪費であり、忘れると本当にわかりにくいバグが発生します。
Thor84no 2013年

私はThor84noに同意します。バイトは数値ではなく、符号を付けるべきではありません。一方、それらは数値ではないため、+演算子と-演算子を使用することも使用することもできません。ビット演算子だけを使用しても問題なく動作しますが、反対に、シフト演算子は希望どおりに機能せず、実際にJavaはシフトされたバイトをintに昇格します。
user1708042 14年

1
@VlastimilOvčáčíkこの場合、文字通り不可能です。それが動機です。あなたx & 0xFFはそれを必要とするbehaveLikeAnUnsignedByte(x)あらゆる場所で繰り返すか、あらゆる場所で何かを繰り返す。これは、符号なしである必要があるバイト値またはバイト配列を使用するすべての場所で必要です。この繰り返しを回避する考えられる方法はありません。バイト変数への単一の参照のみでバイト値を読み書きするプロトコルの実装を作成することはできません。あなたの単純化した見方は、なぜ彼らがそれを修正しようとしないのかを説明するかもしれません。
Thor84no

-1

Javaには符号なしバイトはありませんが、バイトを表示したい場合は、

int myInt = 144;

byte myByte = (byte) myInt;

char myChar = (char) (myByte & 0xFF);

System.out.println("myChar :" + Integer.toHexString(myChar));

出力:

myChar : 90

詳細については、Javaで16進/バイト値を表示する方法を確認してください。


これを自分で定義する必要はありません。java.lang.Byte.toUnsignedInt(byte value);このために存在します。
アレクサンダー-2016

-2

Javaの制限により、現在のデータ型形式では符号なしバイトはほぼ不可能です。あなたが実装しているもののために別の言語のいくつかの他のライブラリに行くことができます、そしてあなたはJNIを使用してそれらを呼び出すことができます。


彼がそれを符号付きバイトとして保存したいとは思わない。彼は署名されたバイトとしてそれを受け取っており、それを完全に有効なintとして保存したいと考えています。彼の問題は、彼が入力を受け取るところはどこでも0から255までの値をバイトとして表すことですが、Javaは符号付きバイトをサポートしていないため、Javaはそれを2の補数の符号付き値として解釈します。
Zac

-2

はいといいえ。私はこの問題を掘り下げています。私がこれを理解するように:

事実は、Javaが整数-128から127に署名しているということです。Javaで未署名を提示することは可能です:

public static int toUnsignedInt(byte x) {
    return ((int) x) & 0xff;
}

たとえば、-12の署名された番号を追加して署名を解除すると、244になります。しかし、その番号を署名で再度使用するには、署名に戻す必要があり、再び-12になります。

244をJavaバイトに追加しようとすると、outOfIndexExceptionが発生します。

乾杯..


3
これを自分で定義する必要はありません。java.lang.Byte.toUnsignedInt(byte value);このために存在します。
アレクサンダー-2016

-3

Javaで符号なしバイトが必要な場合は、関心のある数から256を引くだけです。2の補数が生成されます。負の値でされます。これは、符号なしバイトでの必要な数です。

例:

int speed = 255; //Integer with the desired byte value
byte speed_unsigned = (byte)(speed-256);
//This will be represented in two's complement so its binary value will be 1111 1111
//which is the unsigned byte we desire.

leJOSを使用してNXTブリックをプログラムする場合は、このようなダーティーハックを使用する必要があります。


255のバイナリ値も1111 1111であることを理解しているので、減算は必要ありません。
Nick White

@NickWhite、はい、バイナリで。しかし、Javaは255が11111111ではない2の補数を使用します
XapaJIaMnu

申し訳ありませんが、これは間違っています。いくつかの実験をしてみてください。の値speed_unsignedは署名されています。それを印刷して見てください。(そして、- 256ここでは何も達成しません。)
スティーブンC
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.