Question

I have a simple program to find my IP address and convert it to a String. Why is the b[i] value with (int)255 below?

public class FirstSocketProgramming {  

 public static void main (String arg[]){  

  InetAddress local = null;  

  try {  

   local = InetAddress.getLocalHost();  

  } catch (UnknownHostException e){  

   System.err.println   

      ("Identity Crisis!");  

   System.exit(0);  

  }  

 byte[] b = local.getAddress();  

System.out.println (b.toString());  
System.out.println (b.length);  
 String strAddress="";  

 for (int i = 0; i < b.length; i++)  

   strAddress += ((int)255&b[i]) + ".";  

 System.out.println ("Local = " + strAddress);  

 }  

}
Was it helpful?

Solution

byte data type is based on Two's complement binary signed number representation with a value range from -128 to +127.

Positive values from 0 to 127 have it's most significant bit equal to 0 representing +. Here binary representation is the same as it's numeric value, for example byte 00000100 = int 4

Negative values from -128 to -1 have it's most significant bit equal to 1 representing - However in negative range, Two's complement binary representation is NOT the same as it's numeric value, for example you would expect byte 10000100 to be equal to int 132, but is actually -124. Simply casting a byte to int won't help.

Casting just widens 1 byte to 4 btytes, 10000100 ==> 11111111111111111111111110000100 which is equal to -124, not 132, because int data type is also based on Two's complement. Casting byte into int is a step in the right direction, however you also need to get rid of all these ones in front. 255&b[i] trick achieves that.

This is what happens in 255&b[i]:
According to conversion rules defined in the the JLS & bitwise operator first converts it's operands to int, which means 255&b[i] is the same as ((int)255)&((int)b[i]). When byte is cast to int it just gets wider:

10000100 = byte -124 ==> 11111111111111111111111110000100 = int -124

Then bitwise AND is performed.

11111111111111111111111110000100 = int -124 
&
00000000000000000000000011111111 = int 255
--------------------------------
00000000000000000000000010000100 = int 132

Final result is an int 132

OTHER TIPS

It's converting the signed byte to an integer so that you get the full range of (unsigned) 8-bits, instead of showing a negative number for values over 127.

In Java, since bytes are signed, the max value for a byte is 127. So lets say the number is 128. In an unsigned byte this would be represented as 10000000b. However, with 2's complement negative numbers, this becomes -128. Doing 255 & b[i] coerces the value to an integer (32-bit) and zeroes out the high bits so you get 128 instead of -128.

The address is written as a set of bytes, from 0 to 255. Java interprets each byte as a signed one from -128 to 127. Thus, forming a string from the bytes as signed ones would be meaningless, for example -18.14.87.-45. This does not match the IP representation.

(int)255&b[i]

casts b[i] to an int while widening it, thus ignoring sign and reading it as unsigned. The (int) is frivolous as 255 is already interpreted as something wider than 8 bits. The 0-255 value is concatenated aftwerwards. You thus get an IP like 192.168.1.200(note that this address does not match the erronous one given before).

As a general thing doing 255&foo (or any 2^n-1 for integer n, like 65536, or even in hex like 0xFF) is an attempt to cast bit lengths safely.

The ip address is logical and with the subnet_mask to find the net_id and the host_id. In the example it's the same but very unusual. The subnet_mask can be used to carve out many net_id. Read here for an example: http://www.garykessler.net/library/subnet_masks.html.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top