VansFannel
VansFannel

Reputation: 45931

Convert char[] to byte[] without losing 'bits'

I'm developing an Android 2.3.3 application with Java.

This app is an iOS code with unsigned data types port to Java.

On iOS it works with UInt16 and UInt8. In one case instead using byte[] I'm using char[].

But know I have to send that char[] as a byte[] using a DatagramPacket.

If one element of char[] is 128, how can I do to insert into byte[] and the receiver gets 128. I don't know what happens if I do this:

char c = (char)128;
byte b = (byte)c;

Which will be b value?
128 = 10000000. b = -1 or b = 127?

How can I convert char[] to byte[] without losing any bits?

Upvotes: 1

Views: 6371

Answers (2)

David Wasser
David Wasser

Reputation: 95588

In Java char is an unsigned 16-bit quantity. So you can directly convert your uint16 to char without doing anything else.

For unsigned 8-bit quantity you have 2 options:

  1. Use byte. It also holds 8 bits. You don't lose any bits just because it is signed. However, if you do arithmetic with it you need to remember that Java will scale byte up automatically to an int and sign-extend it. To prevent this just always mask it like this:

    byte b; int foo = 5 * (b & 0xFF);

  2. Use char. It is unsigned and can hold 16 bits so the 8 bits will fit in there quite nicely. To put a byte into a char just do this:

    byte b; char c = (char)(b & 0xFF); // Mask off the low-order 8 bits

To put a char into a byte just do:

char c;
byte b = (byte)c; // Truncates to 8 bits

Be aware that byte in Java is signed, so that whenever you do arithmetic with it you need to mask the low-order 8 bits only (to prevent sign-extension). Like this:

byte b;
int foo = (b & 0xFF);

You can do all the normal bitwise operations you want with a byte without having to mask:

byte b;
if (b & 0x80) ... // Test a flag
b |= 0x40; // Set a flag
b ^= 0x20; // Flip a flag from 0 to 1 or 1 to 0
b ^= ~0x10; // Clear a flag
byte x = b << 3; // Shift left 3 bits and assign
byte x = b >>> 4; // Shift right 4 bits and assign (WITHOUT sign extension)

Upvotes: 8

T.J. Crowder
T.J. Crowder

Reputation: 1074666

I think you need to rethink your approach so you don't end up needing to convert char[] to byte[].

If your data really is characters, then you want to look at various serialization techniques, such as using new String(char[]) to create a string and then using getBytes(Charset) to get the bytes as encoded by a given Charset (because, of course, the same characters result in different bytes when encoded in ASCII or UTF-8 or UTF-16, etc.).

But from your question, it sounds like you're not really using characters, you're just using char as a 16-bit type. If so, doing the conversion isn't difficult, something along these lines:

byte[] toBytes(char[] chars) {
    byte[] bytes = new byte[chars.length * 2];
    int ci, bi;
    char ch;

    bi = 0;
    for (ci = 0; ci < chars.length; ++ci) {
        ch = chars[ci];
        bytes[bi++] = (byte)((ch & 0xFF00) >> 8);
        bytes[bi++] = (byte)(ch & 0x00FF);
    }

    return bytes;
}

Reverse the masks if you want the result to be small-endian instead.

But again, I would look at your overall approach and try to avoid this.

Upvotes: 2

Related Questions