Search code examples
javaintegerbitwise-operatorsbitmask8-bit

Hexadecimal: Set an 8-bit byte in an int


In Java:

I have a 32-bit number given to me in hexadecimal form. I'm given a specific byte number (0-3, 0 for least-significant byte) and told that I need to replace that byte with another byte also given to me in hexadecimal form. Ex: 32-bit number 0xAAA5BBC6, replace byte 1 with 0x17 to get 0xAAA517C6.

I can't use any casting, multiplication, addition, subtraction, or conditionals. I cannot write any helper methods, or call any other method from this or another file to implement any method. Additionally, this has to be written in one line of code.

I believe I should be using masking, but I can't figure out where to start. Given a byte number, how can I change all 8 bits. Toggling one off or on is easy, but toggling all 8 bits to be a certain value?


Solution

  • In one line, assuming that bytes are being counted from the least significative byte:

    int updatedValue = originalValue & ~(0xFF << (byteNumber << 3)) | ((((int)newByte) & 0xFF) << (byteNumber << 3));
    

    Where:
    originalValue is your original 32-bit integer
    newByte is the byte you are given to replace the old byte
    byteNumber is the byte number (0-3)

    what the code does is the following:

    • create a mask to "delete" the old byte (clear the bits of this byte). In order to create the mask:

      • create a mask of a byte of all bits set (all in 1) 0xFF
      • offset this mask to the position of the byte to be "deleted", it has to be 8 times the number of the byte to be "deleted". As I can't multiply (part of your restrictions), then I offset this number 3 bits to the left (which is equivalent to multiply by 8, remember that displacing the bits one position to the left is equilavent to multiply by 2, so an offset by 3 will be 2 * 2 * 2 = 8) this is done by this piece of code: (byteNumber << 3)
      • "toggle" the bits of the mask with ~, so I have the mask to "delete" the byte: ~(0xFF << (byteNumber << 3)) at this point you mask would be, say FFFF00FF if you wanted to clear byte #1
    • perform an and-bit-wise operation between the original number and the mask created in the first step: ~(0xFF << (byteNumber << 3))

    • create a 32bit integer with the new byte and offset its bits to the position of the byte. Again, the offset is done with (byteNumber << 3) which has already been explained.
    • perform an or bit-wise operation with the result of the second step to set the bits of the new byte (this is the line of code, the final step)

    Now, the reason for which I'm doing ((int)newByte) & 0xFF) instead of just ((int)newByte)) or just newByte, is that the JVM promotes to int the operator byte before doing the operation <<, this can have undesired effects if your newByte is bigger than 0x7F (for instance, a value of 0x80 would be cast to int as 0xFFFFFF80 instead of 0x00000080). By doing ((int)newByte) & 0xFF) I'm doing the promotion to int by myself and clear undesired bits just in case.