This question already has answers here:
Odd behavior when Java converts int to byte?
(12 answers)
Closed 9 years ago.
int i = 234;
byte b = (byte) i;
System.out.println(b); // -22
int i2 = b & 0xFF;
System.out.println(i2); // 234
I was looking at this code and was confused about how they values were stored. The first int is stored as 32 bits (4 bytes). b converts to binary and stores its signed value (8 bits). Does i2 store it as an 8 bit unsigned representation or does it convert it back to 32 bits?
Java does not have unsigned primitive types. All byte variables are signed 8-bit values.
Whether or not the most significant bit is interpreted as a sign bit, when you do bit-wise operations all the bits that are present are used by the operator. To make this concrete, the following are equivalent:
i2 = b & 0xFF;
i2 = b & ((byte) -1);
i2 is declares as an int, so it should be a full 32-bit value. It will contain the binary AND of b, which in this case is the lower 8 bits and 0xFF.
Things aren't "stored as" an unsigned or signed representation. This is a nitpicky distinction, but it seems to be where you're getting confused. The only difference is how the bits are interpreted. What's happening here is the following:
i stores the value 11101010 (plus some number of higher order bytes). Under Java's convention for integer storage format, this represents the value 234.
b stores the value 11101010, since ints are converted to bytes by simply truncating them. Under Java's convention for numerical byte storage format, this represents the value -22.
i2 stores the value 11101010 (plus some number of higher order bytes), because a bitwise operation was applied to b so its bits were directly copied. (Had you written int i2 = b or int i2 = b + 0, the byte would have been converted to its numerical value -22, and then stored as the int representation of -22.
Related
I have question regarding my code here:
public class Main
{
public static void main(String[] args) {
System.out.println("Hello World\n");
int x = 36;
byte b1 = ((byte) x) & ((byte) 0xff); // it seems it is the part after &, but I have 0xff cast to byte by using (byte)0xff, so not sure where exactly the error is coming from.
System.out.println(b1);
}
}
I am not sure exactly which part is causing the error of:
incompatible types: possible lossy conversion from int to byte
This is the error message output from the program:
You appear to be confused.
There is no point in your code. taking any number, calculating that & 0xFF, and then storing it in a byte, is always a noop - it does nothing.
You additionally get an error because & inherently always produces at least an int (it'll upcast anything smaller to match), so you're trying to assign an int to a byte.
What are you trying to accomplish?
"I want to have my byte be unsigned"!
No can do. Java doesn't have unsigned bytes. A java byte is signed. Period. It can hold a value between -128 and +127. For calculation purposes, -128 and 255 are identical (they are both the bit sequence 1111 1111 - in hex, 0xFF, and they act identically under all relevant arithmetic, though it does get tricky when converting them to another numeric type int).
"I just want to store 255"!
Then use int. This is where most & 0xFF you'll ever see in java code comes from: When you have a byte value which java inherently treats as signed, but you wish to treat it as unsigned and, therefore (given that in java bytes can't do that), you want to upcast it to an int, containing the unsigned representation. This is how to do that:
int x = y & 0xFF;
Where y is any byte.
You presumably saw this somewhere and are now trying to apply it, but assigning the result of y & 0xFF to a byte doesn't mean anything. You'd assign it to an int variable, or just use it as expression in a further calculation (y & 0xFF is an int - make sure you add the appropriate parentheses, & has perhaps unexpected precedence).
int x = 36;
byte b1 = ((byte) x) & ((byte) 0xff);
Every imaginable way of this actually working would mean that b1 is... still 36.
To compute x & y where the two operands are bytes, they must first be promoted to int values. There is no & between bytes. The result is therefore of type int
That is, what you wrote is effectively evaluated as if you'd written it as the following, making explicit what the language gives you implicitly:
byte b1 = ((int) (byte) x) & ((int) (byte) 0xff);
Just do the arithmetic and then cast the result to byte.
byte b1 = (byte)(x & 0xff);
Link to Java Language Specification
Edited to add, thanks to #rzwitserloot, that masking a byte value with 0xff is however pointless. If you need the assignment from an integer to a byte, just write the cast:
byte b1 = (byte)x;
This question already has answers here:
Java byte array contains negative numbers
(5 answers)
Closed 6 years ago.
I have the following problem. I'm using Java to create a byte array from a file. So I do the following:
byte[] myByteArray = Files.readAllBytes(filename);
However, for many of the bytes it is returning incorrect/negative values.
For instance, if I test using javascript, to read every byte of a file e.g.
function readbytes(s){
var f = new File(s);
var i,a,c;
var d = [];
if (f.isopen) {
c = f.eof;
for(i=0;i<c ;i++){
a = f.readbytes(1);
d.push(a);
}
f.close();
return d;
} else {
post("could not open file: " + s + "n");
}
}
(readbytes is a function in the program Im using that gives the byte at a specific position).
This returns the correct bytes
So Im wondering, why does java return incorrect codes? Is this something to do with unsigned values?
Java doesn't know unsigned bytes. For instance the unsigned byte 255 would be printed as its signed version -1. In memory however, the actual value would be the same and represented as 255.
If you'd like to convert a byte to its unsigned representation, you may use the bitwise AND operator.
For instance:
bytes[x] & 0xff
Java doesn't know about bytes at runtime either for any operand that may be pushed onto the Java virtual machine's stack. In fact every operation you apply to an integral value results in an integer. That's why ((byte)-1) & 0xff) results in an integer and its value is 255. If you would like to store that value back into a byte, you'd have to cast it to byte again, which of course, is -1.
byte x = -1; // java is friendly enough to insert the implicit cast here
System.out.println(x); // -1
System.out.println(x & 0xff); // 255
byte y = (byte)(x & 0xff); // must add (byte) cast
System.out.println(y); // -1
Also keep in mind that technically the output you see is different but the content is still the same since you can map from Java's signed byte always to its unsigned representation. Ideally, you'd use something like DataInputStream which offers you int readUnsignedByte().
I am trying to construct an IP header.
An IP header has the following fields: Version, IHL, DSCP etc. I would like to populate a Byte Array such that I can store the information in bytes.
Where I get confused however is that the Version field is only 4 bits wide. IHL is also only 4 bits wide. How do I fit the values of both of those fields to be represented as a byte? Do I need to do bitshifting?
E.g. Version = 4, IHL = 5. I would need to create a byte that would equal 0100 0101 = 45h or 69 decimal.
(byte) (4 << 4) | 5
This shifts the value 4 to the left, then sets lower 4 bits to the value 5.
00000100 A value (4)
01000000 After shifting left 4 bits (<< 4)
00000101 Another value (5)
01000101 The result of a bitwise OR (|) of #2 and #3
Because the operands are int types (and even if they were byte values, they'd be promoted to int when operators like | act on them), the final result needs a cast to be stored in a byte.
If you are using byte values as operands in any bitwise operations, the implicit conversion to int can cause unexpected results. If you want to treat a byte as if it were unsigned in that conversion, use a bitwise AND (&):
byte b = -128; // The byte value 0x80, -128d
int uint8 = b & 0xFF; // The int value 0x00000080, 128d
int i = b; // The int value 0xFFFFFF80, -128d
int uintr = (b & 0xFF) | 0x04; // 0x00000084
int sintr = b | 0x04; // 0xFFFFFF84
You can do something like this:
int a = 0x04;
a <<= 4;
a |= 0x05;
System.out.println(a);
which essentially turns 0b00000100 into 0b01000000, then into 0b01000101.
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html
To make a compact field containing both Version and IHL in one byte, try doing
byte b = (byte)((Version << 4) + IHL);
This will only work if Version and IHL are numbers from 0 to 15
Just because a byte is 8 bits and your values can only be a maximum of 4 is not a problem. The extra 4 bits will just always be zeroes.
So if you were storing 1 for example:
0000 0001
or 15 (which is the maximum value right?):
0000 1111
Byte shifting is not possible in Java.
How does bitshifting work in Java?
However, as far as the logic is concerned, if you want the version and IHL in one byte, you could do it using the following
byte value = (byte) (IHL | VERSION << 4);
Taking me hours already to figure this out by googling and I think need help here. I have a snippet that is causing it not to work like its equivalent in objective c so would need some experts' help.
What are the equivalent of the objective c snippets below in java?
unsigned char mByte[CC_SHA1_DIGEST_LENGTH];
uint64_t tBytes = 0xFFFFFFFF;
Well there is no absolute equivalent, if all languages were the same why would we need more than one?
The closest thing is probably:
final int CC_SHA1_DIGEST_LENGTH = 1024; //some length
char[] mByte = new char[CC_SHAR1_DIGEST_LENGTH];
//there is no unsigned keyword in java
//The long data type is a 64-bit two's complement integer
long tBytes = Long.MAX_VALUE;
long tBytes=0xFFFFFFFF; would also work, but this is a negative number (because it is treated as an integer, not a long). If you want it to be long you need to add L (0xFFFFFFFFL) at the end. Be careful!
More info on the primitive datatypes can be found here.
unsigned char mByte[CC_SHA1_DIGEST_LENGTH];
equivalent in java will be
final int CC_SHA1_DIGEST_LENGTH=1024;
byte mByte[CC_SHA1_DIGEST_LENGTH];
though mByte is unsigned so when you work with mByte array you have to convert byte value to unsigned using 0xFF.
for example,
mByte[0]=(0x88 & 0xFF);
uint64_t tBytes = 0xFFFFFFFF;
equivalent in java will be
long tBytes = 0xFFFFFFFF;
Well the rule of thumb would be to match type lenght's in bits.
In C unsigned char is 8 bit wide, so Java equivalent would be byte.
In C uint64_t is 64 bit wide, so Java equivalent would be long.
So therefore Java equivalent would be:
//SHA1 lenght would be 20 bytes
public static final int CC_SHA1_DIGEST_LENGTH = 20;
byte mBytes[] = new byte[CC_SHA1_DIGEST_LENGTH];
long tBytes = 0xFFFFFFFF;
#user3200809
mByte[0]=(0x88 & 0xFF); - this operation is pointless unless you have value larger than 8 bits.
See the same operation in binary:
1000 1000
&
1111 1111
=
1000 1000
When assigning to mByte[i] you would have to type cast to byte anyway so all excessive bits will be chopped.
When we look at memory representation of those types there is no difference between signed and unsigned types.
I'm guessing from authors post that he works with SHA1 algorithm which is bunch of binary operations (xor's, and's, shift's).
So for binary operations there is no difference that type is signed or unsigned:
byte b = (byte) 0x80; //-128 in signed decimal
b ^= (byte) 0x01;
System.out.printf("0x%x", b); // prints 0x81 which is -127 in signed decimal
BUT you could run into problems if you're doing e.g. division.
I know there are N threads for this question but some people are using different and different methods to convert a byte to int. Is this correct what am I writing? Hex to int or hex to decimal? Which one is the correct?
Anyway, why I'm getting 4864 instead of 19 ?
byte[] buffer = ....
buffer[51] = 0x13;
System.out.println( buffer[51] << 8 );
Is this correct what am I writing?
The code you've posted does implicit conversion of int to String, but that will display it in decimal. It's important to understand that a number isn't in either hex or decimal - it's just a number. The same number can be converted to different textual representations, and that's when the base matters. Likewise you can express the same number with different literals, so these two statements are exactly equivalent:
int x = 16;
int x = 0x10;
Anyway, why I'm getting 4864 instead of 19
Because you're explicitly shifting the value left 8 bits:
buffer[51] << 8
That's basically multiplying by 256, and 19 * 256 is 4864.
you are getting 4864 as a result because 4864 is 0x1300 in hex.
if you are expecting 19(0x13) as result then I guess you are trying to do circular shifting.
you can do that using writing like that,
/*hex 0x13 (19 in decimal) is assigned to buffer[51] as int*/
buffer[51] = 0x13;
System.out.println( Integer.rotateRight(buffer[51], 8));