Friday, August 12, 2005

Unsigned char in C <--> Signed byte in Java

ช่วงนี้ได้มีโอกาสใล่ดู algorithm ที่เกี่ยวกับการ encrypt, decrypt
ที่เขียนด้วย C แล้วต้องแปลงให้เป็น java เลยนั่งค้นหาดูว่ามีประเด็นอะไรบ้าง
ที่อาจเป็นปัญหา

ประเด็นแรกก็คือ เรื่อง byte ของ Java เป็น signed byte
แต่ใน c จะเป็น unsigned char
ปัญหาจะเห็นชัด กรณีที่เรา shift bit
เช่น
byte b1 = (byte) 0x80;          // in binary -> 10000000
byte b2 = b1 >> 4;
System.out.println(b2); // print -> -8

byte b1 = (byte) 0x80;
int b2 = b1 >>> 4;
System.out.println(b2); // print 268435448

ปัญหาของกรณีนี้ก็คือ 0x80 พอแปลงเป็น byte แล้ว มันก็คือ -128 (มี sign bit เป็น 1)
พอ shift bit แล้วก็ได้เรื่องเลย
ทางแก้ก็คือ ให้เรา & 0xff กับ byte ก่อน shift
byte b1 = (byte) 0x80;
byte b2 = (byte) ((b1 & 0xff) >> 4);
System.out.println(b2); // print -> 8

byte b1 = (byte) 0x80;
int b2 = (b1 & 0xff) >> 4;
System.out.println(b2); // print -> 8

การแปลง byte เป็น int ก็ใช้กฎเดียวกัน
byte b1 = (byte) 0x80 ;
int i1 = b1 & 0xff;
int i2 = b1;
System.out.println(i1); // print 128
System.out.println(i2); // (wrong for unsigned byte) print -128


ที่นี้บางครั้งที่เราต้องการแปลง byte array ให้เป็น int value หรือ long value
ก็ใช้การ & 0xff เช่นเดียวกัน
ตัวอย่างเช่น
public static int toInt(byte[] bs) {
return ((bs[3] & 0xFF) << 0) +
((bs[2] & 0xFF) << 8) +
((bs[1] & 0xFF) << 16) +
((bs[0] & 0xFF) << 24);
}

เราสามารถดูตัวอย่าง source code ของ Java
ได้ที่ class java.io.Bits ซึ่งถูกเรียกใช้จาก
ObjectInputStream, ObjectOutputStream
น่าเสียดายที่ class นี้ไม่ได้ประกาศเป็น public class
ทำให้ไม่สามารถเรียกใช้งานในโปรแกรมเราได้

Related link from Roti

No comments: