Sign(+/-) error in byte in Java byte setting operations - java

I am declearing in Java
public byte[] orbits = new byte[38];
Now if I am doing
orbits[24] = (byte)0xFF;
orbits[24] should get populated by 11111111 i.e FF(in hexadecimal) but instead its getting populated with -1.
This operation in C++ working perfectly
char orbits[38]
orbits[24] = (char)0xFF;
How to replicate the similar situation in Java using byte?
Thanks

Well, it just happens that -1 is 0xFF. Everything is correct. byte stores values from -128 to 127 using two's complement.
In Java there are no unsigned types. If you want to use bit patterns, then use byte. 0xFF and -1 are the same thing in this situation. If you want to use numbers, that is, 0xFF is actually 255 and not -1, then you need to use a bigger type, like short.

Related

In java, how come method read() from FileInputStream works does not throw " incompatible types: possible lossy conversion"?

I am currently going through Java I/O tutorial and having hard time understanding the read() method of FileInputStream class. I know that per documantion that read() method reads "byte" of data from stream and returns an integer representing the byte (between 0 and 256) or -1 if it reaches the end of file.
Byte in java has a range between -128 and 127, so, how come when I edit xanadu.txt and add ASCI symbol "ƒ" (which has a decimal value of 131), java does not complain by throwing an error that value 131 is out of range defined by byte (-128 and 127)? When I try to test this using literals I get two different results.
The following works:
byte b = 120;
int c = b;
System.out.println((char)c);
Output: x
But this does NOT work (even though it works when added to xanadu.txt):
byte b = 131;
int c = b;
System.out.println((char)c);
Output: error: incompatible types: possible lossy conversion from int to byte
byte b = 131;
I tried explicitly casting using byte: (how is this possible?)
byte b = (byte)131;
int c = b;
System.out.println((char)c);
Output: テ
I am total newbie when it comes to I/O streams, somebody please help me understand it.
EDIT: Turns out my knowledge on concepts of type casting was lacking, specifically in understanding the difference between "Widening" and "Narrowing". Reading up more about these concepts helped me understand why explicit (aka narrowing) casting works.
Allow me to explain: Look at the 3rd code block where I am explicitly casting the literal '131' to type of byte. If we are to convert the literal 131 into binary form of 32-bit signed 2's complement integer, we will get 00000000 00000000 00000000 10000011 which is 32-bits or 4 bytes. Recall that Java data type 'byte' can only hold 8-bit signed 2's complement integer, so, 131 is out of range and thus we get error "possible lossy conversion from int to byte". But, when we explicitly cast it to byte, we are 'chopping off' or correct term would be 'narrowing' the binary down to 8 bit integer. So, when we do that, then the resulting binary is 10000011 which is -125 in decimal value. Since -125 is in range of -128 and 127, byte has no issues accepting and storing it. Now when I try to story the value of byte in int c, implicit or "widening" casting takes place, where -125 in binary form of 8-bit 10000011 is converted into equivalent -125 in binary form of 32-bit 11111111 11111111 11111111 10000011. Finally, system.out is trying to output the value of (char)c which is another explicit or "narrowing" casting where its trying to shrink from 32-bit signed to 16-bit unsigned. When casting is complete, we get 11111111 10000011 in binary form. Now, when this binary is converted into character form by java, it returns テ.
I can conclude by saying that it helps converting everything into binary form and go from there. But make sure you understand encoding and 2's complement
I don't know where you got the value 131 from, but as far as I am concerned, LATIN SMALL LETTER F WITH HOOK (ƒ) is not in the original ASCII character set, but in extended ASCII, with a decimal value of 159. See here. It is also encoded in UTF-16 (how Java chars are encoded) as hex 192 (decimal value 402).
First, ensure that your text files are encoded in extended ASCII, and not UTF-8 (which is the most likely encoding). Then you can use a FileInputStream to read the file, and you will get 159.
Note that 159 is outside the range of the the Java byte type. This is fine, because read returns an int. If the text file is encoded in UTF-8 however, ƒ is encoded in 2 bytes, so read will be reading one byte at a time.
Your second code block doesn't work because as you said, byte goes from -128 to 127, so 131 obviously doesn't fit.
Your third code block forces 131 into a byte, which causes overflow and the value "wraps back around" to -125. b and c are both -125. When you cast this to a char it becomes 65411 because this conversion involves padding the whole number to 16-bits first, then treating it as an unsigned integer.
The reason why this all works when you use FileInputStream.read instead of doing these conversions yourself, is because read actually returns an int, not a byte. It's just that the int it returns will always be in the range -1 ~ 255. This is why we say "read returns a byte", but its actual return type is int.
byte b = 131; // this is 8 bits type, but >8 bits value
int c = b; // this is 32 bits type
System.out.println((char)c); // this is 16 bits type
Output: error: incompatible types: possible lossy conversion from int to byte
byte b = 131;
The two-complement encoding of 131 is:
2^7+2^1+2^0
^^^
sign bit
131 won't fit in a signed byte without an overflow in the two complement representation that is used for signed types. The highest bit=sign bit is set which gets extended when casting from byte to int.
The Java compiler notices that 131 won't fit properly in a byte which leads to the error.

Is possible have byte from 0 to 255 in java?

I have system (in c#) to control user access.
I need to have the same access controller in java for an specific case.
This controller has a criptography algorithm (rijndael).
My problem is that this algorithm uses arrays of bytes (byte[]); and this byte type in c# is 0 to 255, and in java is -128 to 127. This difference generate differents results.
How can I make those two codes to use the same byte array?
PS: I can't change the c# code; if I could, I would use sbyte instead of byte.
When you read an unsigned byte[] into a signed byte[] none of the bits are harmed in this progress and no data is lost. The difference is only how the top bit is treated. If you want to turn a signed byte in a value between 0 and 255 you can & it with 0xFF e.g.
int value = bytes[i] & 0xFF;
Someone developed a library for unsigned types you might be able to use:
https://github.com/jOOQ/jOOU

How to send value bigger than 127 in byte Java

I am working on an Smart Card where there is a method in javax.smartcardio.CommandAPDU.
CommandAPDU(int cla, int ins, int p1, int p2, byte[] data, int ne)
I need to send data as byte[] (5th argument). Now my problem is that, as Java primitive data types are signed the max value of a byte can not exceed 127. I need to send a value bigger than 127. To be precise, the hex value 94 which is equal to 148.
As some solution suggests that we can cast it to integer.
byte b = -108;
int i = b & 0xff;
I can't do that as the CommandAPDU(); constructor doesn't take an []. So how to do it?
Depending on how it is interpreted by the smart card, you could just send the correct negative value. If the smart card interprets value as unsigned, you could for example send -1 for 255.
You're calculating the APDU with unsigned bytes, while Java uses signed bytes.
It's just a matter of how the data is interpreted, sending -108 to the smart card will be interpreted in exactly the same way as sending 148 from a platform using unsigned bytes. The bit combination is exactly the same.
Java can even do the conversion itself so that you can write the code using unsigned numbers;
byte data = (byte)0x94; // stores -108 in "data", which will be interpreted
// as 148 on an unsigned platform
For long blocks of data, it is probably best to use a hexadecimal encoder/decoder. But be sure that you handle the data as bytes internally (directly decode and don't look back to the hex String). The Apache codec library contains a good encoder/decoder, or you can use Bouncy Castle or Guava or use one of the many examples on SO.

How to read unsigned values from files

I am trying to read binary data (Doom WAD files), which contain a lot of unsigned short and unsigned byte values.
At the moment I read the file into a byte[], wrap a ByteBuffer with little-endian order around it and access the values by bbuf.getShort() etc. respectively.
Converting those e. g. to 2D-coordinates is not a problem, because in the end it won't matter if they range eg. from -128 to 128 or from 0 to 256, but more often the short values are used as array indices and short/byte values as flags/, so I need a fast way to treat them as signed types.
I know, Java doesn't have unsigned types "for sake of simplicity...".
Can you make any suggestions?
In order to save unsigned ints you need a long. Then you need to truncate last 32 bits. You can use following trick to do it.
final long UNSIGNED_INT_BITS = 0xffffffffL;
int a = -3;
long b = UNSIGNED_INT_BITS & a;
System.out.println(a);
System.out.println(b);
System.out.println(Long.toHexString(UNSIGNED_INT_BITS));
Output:
-3
4294967293
ffffffff
If all else fails, you could always store them internally as ints and make sure you do proper conversion when reading/writing.
(Read as byte/short, cast to int, add 2^bits if negative. Just truncate to 8/16 bits when writing.)
Hardly the most elegant solution, I admit.
If you need to interprete 0xFF byte as 256 do the following
int n = b & 0xFF;

When casting a small integer type to a wider one, is it safe to rely on &ing with a mask to remove the sign?

I have code that stores values in the range 0..255 in a Java byte to save space in large data collections (10^9 records spread over a couple hundred arrays).
Without additional measures on recovery, the larger values are interpreted as being negative (because the Java integer types use two's complement representation).
I got this helpful hint from starblue in response to a related question, and I'm wondering if this technique is safe to rely on:
int iOriginal = 128, iRestore;
byte bStore = (byte) iOriginal; // reading this value directly would yield -128
iRestore = 0xff & bStore;
Yes, it's safe, indeed it's the most effective way of converting a byte into an (effectively) unsigned integer.
The byte half of the and operation will be sign-extended to an int, i.e. whatever was in bit 7 will be expanded into bits 8-31.
Masking off the bottom eight bits (i.e. & 0xff) then gives you an int that has zero in every bit from 8 - 31, and must therefore be in the range 0 ... 255.
See a related answer I gave here.

Categories