0

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.

jdie8274j
  • 155
  • 1
  • 10

5 Answers5

0

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

phflack
  • 2,729
  • 1
  • 9
  • 21
  • `Type mismatch: cannot convert from int to byte` – erickson Nov 05 '15 at 17:54
  • I'm using bytes for Version and IHL and not receiving the error – phflack Nov 05 '15 at 17:56
  • `<<` is okay, actually, but `+` performs binary promotion to an `int` or `long`, depending on the widest operand. What are you compiling with? You might want to switch, as this code is invalid according to the [language specification](https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.6.2) – erickson Nov 05 '15 at 18:02
  • @erickson Probably like a two week old version of javac and java on Debian (pretty sure it's Debian) – phflack Nov 05 '15 at 18:08
  • 1.8.0_25-b17 says, `error: incompatible types: possible lossy conversion from int to byte`, 1.7.0_67-b01 says `error: possible loss of precision`. Eclipse gave the message I show above. You also have the the citation from the JLS. – erickson Nov 05 '15 at 18:12
  • @erickson Trying to reproduce how it managed to compile, and discovered that somehow `byte b = (5 << 4) + 4;` works, the numbers can be casted as an int or as a byte and still work, but any usage of actual variables breaks it, while casting the values does not – phflack Nov 05 '15 at 18:17
  • Yes, if you use compile-time constants, the compiler actually computes the value and stores it. The compiled byte code is exactly the same as if you wrote `byte b = 0x54;` However, `byte b = (0x08 << 4) | 0x04;` won't compile, because the result is too big for a `byte`. Also, if variables are used in the expression, as they are in your answer, it's a compile-time error, because the result of the right-hand side is an `int`, according to the JLS. – erickson Nov 05 '15 at 18:26
  • Did you want to correct your answer so that I can remove the downvote? – erickson Nov 05 '15 at 20:23
  • It's changed, and Java handles bytes really strangely in comparison to ints – phflack Nov 05 '15 at 20:47
0

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.

ergonaut
  • 6,929
  • 1
  • 17
  • 47
0
(byte) (4 << 4) | 5

This shifts the value 4 to the left, then sets lower 4 bits to the value 5.

  1. 00000100 A value (4)
  2. 01000000 After shifting left 4 bits (<< 4)
  3. 00000101 Another value (5)
  4. 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
erickson
  • 265,237
  • 58
  • 395
  • 493
  • `byte Version = 5; byte IHL = 4; byte b = (Version << 4) + IHL;` compiles fine, no casting needed – phflack Nov 05 '15 at 17:49
  • Thanks @Erickson - great answer. – jdie8274j Nov 05 '15 at 17:52
  • Probably would be best with just the top portion, before introducing ints into the answer – phflack Nov 05 '15 at 17:53
  • Then why can I compile it without errors, just using bytes and without casting? – phflack Nov 05 '15 at 17:54
  • What compiler should I be using for testing things like this? `byte b = (((byte)5) << 4) + ((byte)4); System.out.println(b);` works on Oracle's JDK 8u65 for mac – phflack Nov 05 '15 at 18:33
  • @phflack My answer is written with the assumption that some of the inputs will actually be variables. In practice, you wouldn't write `byte b = (4 << 4) | 5`, you'd just write `byte b = 0x45;`, which is identical from from the compiler's point of view. But if the version or header length is a variable (not a compile-time constant), operations like `+` and `|` will require a cast to a `byte`. – erickson Nov 05 '15 at 18:50
-1

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

thatidiotguy
  • 8,701
  • 13
  • 60
  • 105
-1

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);
Community
  • 1
  • 1
ffff
  • 2,853
  • 1
  • 25
  • 44
  • You seem to have Java confused with some other language, where a char would be equivalent to a byte. – VGR Nov 05 '15 at 17:41