2010-10-02 37 views
8

Vì vậy, tại nơi làm việc hôm qua, tôi phải viết một ứng dụng để đếm các trang trong một tệp AFP. Vì vậy, tôi dusted off MO của tôi: DCA spec PDF và tìm thấy các lĩnh vực có cấu trúc BPG (Begin Page) và định danh 3 byte của nó. Ứng dụng cần chạy trên một hộp AIX, vì vậy tôi quyết định viết nó trong Java.Hiểu các byte Java

Để đạt hiệu quả tối đa, tôi quyết định rằng tôi sẽ đọc 6 byte đầu tiên của mỗi trường có cấu trúc và sau đó bỏ qua các byte còn lại trong trường. Điều này sẽ làm cho tôi:

0: Start of field byte 
1-2: 2-byte length of field 
3-5: 3-byte sequence identifying the type of field 

Vì vậy, tôi kiểm tra các loại hình trường và tăng số đếm trang nếu nó BPG, và tôi không nếu nó không. Sau đó, tôi bỏ qua các byte còn lại trong trường thay vì đọc qua chúng. Và ở đây, trong việc bỏ qua (và thực sự trong chiều dài trường) là nơi tôi phát hiện ra rằng Java sử dụng các byte đã ký.

Tôi đã thực hiện một số công cụ tìm kiếm và tìm thấy khá nhiều thông tin hữu ích. Hữu ích nhất, tất nhiên, là hướng dẫn để thực hiện một bitwise & đến 0xff để nhận giá trị int chưa ký. Điều này là cần thiết cho tôi để có được một chiều dài có thể được sử dụng trong việc tính toán số byte để bỏ qua.

Bây giờ tôi biết rằng tại 128, chúng tôi bắt đầu đếm ngược từ -128. Những gì tôi muốn biết là làm thế nào hoạt động bitwise hoạt động ở đây - cụ thể hơn, làm thế nào tôi đến đại diện nhị phân cho một số âm.

Nếu tôi hiểu bitwise & đúng cách, kết quả của bạn bằng một số chỉ có các bit chung của hai số được đặt. Vì vậy, giả sử byte b = -128, chúng ta sẽ có:

b & 0xff // 128 

1000 0000-128 
1111 1111 255 
--------- 
1000 0000 128 

Vì vậy, làm thế nào tôi sẽ đến ở 1000 0000 cho -128? Làm thế nào tôi sẽ nhận được biểu diễn nhị phân của một cái gì đó ít rõ ràng như -72 hoặc -64?

Trả lời

18

Để có được biểu diễn nhị phân của một số âm bạn tính toán hai của bổ sung:

  • Lấy biểu diễn nhị phân của số dương
  • Invert tất cả các bit
  • Thêm một

Hãy làm -72 làm ví dụ:

0100 1000 72 
1011 0111 All bits inverted 
1011 1000 Add one 

Vì vậy, biểu diễn nhị phân (8 bit) của -72 là 10111000.

Điều thực sự xảy ra với bạn là như sau: Tệp của bạn có byte có giá trị 10111000. Khi được hiểu là byte chưa ký (có thể là những gì bạn muốn), đây là 88.

Trong Java, khi byte này được sử dụng làm int (ví dụ vì read() trả về một int, hoặc vì quảng cáo ngầm), nó sẽ được hiểu là một byte đã ký và mở rộng bằng ký hiệu thành 11111111 11111111 11111111 10111000. Đây là một số nguyên có giá trị -72.

By ANDing với 0xff bạn giữ lại chỉ có 8 bit thấp nhất, vì vậy số nguyên của bạn bây giờ là 00000000 00000000 00000000 10111000, đó là 88.

+0

+1 để đề cập đến hoạt động xảy ra trong phần int có đuôi mở rộng. –

+4

Đây chính xác là những gì tôi đã làm sau, cảm ơn bạn rất nhiều.Đây là lý do tại sao tôi yêu Stackoverflow. –

0

Để nhận giá trị byte chưa ký, bạn cũng có thể.

int u = b & 0xFF; 

hoặc

int u = b < 0 ? b + 256 : b; 
2

Những gì tôi muốn biết là làm thế nào các hoạt động Bitwise làm việc ở đây - cụ thể hơn, làm thế nào tôi đến biểu diễn nhị phân cho một số âm.

Biểu diễn nhị phân của số âm là số bit dương tương ứng được lật với 1 được thêm vào. Biểu diễn này được gọi là two's complement.

1

Tôi đoán phép thuật ở đây là byte được lưu trữ trong một thùng chứa lớn hơn, có thể là một int 32 bit. Và nếu byte được hiểu là byte ký thì nó được mở rộng để biểu diễn cùng số trong int 32 bit, đó là nếu bit quan trọng nhất (bit đầu tiên) của byte là 1 thì trong int 32 bit các bit còn lại của số 1 cũng được chuyển thành 1 (đó là do cách số âm được biểu diễn, phần bù của hai).

Bây giờ, nếu bạn & 0xFF rằng int bạn cắt bỏ những cái 1 và kết thúc với một "tích cực" int đại diện cho giá trị byte bạn đã đọc.

0

Đối với byte với bit 7 bộ:

unsigned_value = signed_value + 256 

toán học khi bạn tính toán với byte bạn tính modulo 256. Sự khác biệt giữa ký và unsigned là bạn chọn các đại diện khác nhau cho các lớp tương đương, trong khi biểu diễn bên dưới như là một mẫu bit giữ nguyên cho mỗi lớp tương đương. Điều này cũng giải thích tại sao cộng, trừ và phép nhân có kết quả tương tự như một mẫu bit, bất kể bạn tính toán với các số nguyên đã ký hoặc chưa ký.

1

Không chắc chắn những gì bạn thực sự muốn :) Tôi giả sử bạn đang hỏi cách trích xuất giá trị nhiều byte đã ký? Trước tiên, hãy xem điều gì xảy ra khi bạn đăng ký mở rộng một byte đơn:

byte[] b = new byte[] { -128 }; 
int i = b[0]; 
System.out.println(i); // prints -128! 

Vì vậy, dấu hiệu được mở rộng chính xác đến 32 bit mà không thực hiện bất kỳ điều gì đặc biệt. Byte 1000 0000 mở rộng chính xác đến 1111 1111 1111 1111 1111 1111 1000 0000. Bạn đã biết cách ngăn chặn phần mở rộng dấu bằng AND'ing với 0xFF - đối với các giá trị nhiều byte, bạn chỉ muốn ký hiệu của byte quan trọng nhất là extendet và các byte ít ý nghĩa mà bạn muốn để điều trị như unsigned (ví dụ giả định mạng thứ tự byte, 16-bit int value):

byte[] b = new byte[] { -128, 1 }; // 0x80, 0x01 
int i = (b[0] << 8) | (b[1] & 0xFF); 
System.out.println(i); // prints -32767! 
System.out.println(Integer.toHexString(i)); // prints ffff8001 

bạn cần phải ngăn chặn phần mở rộng dấu hiệu của mỗi byte ngoại trừ một quan trọng nhất, vì vậy để trích xuất một int 32 bit có chữ ký thành 64-bit dài:

byte[] b = new byte[] { -54, -2, -70, -66 }; // 0xca, 0xfe, 0xba, 0xbe 
long l = (b[0]   << 24) | 
     ((b[1] & 0xFF) << 16) | 
     ((b[2] & 0xFF) << 8) | 
     ((b[3] & 0xFF)  ); 
System.out.println(l); // prints -889275714 
System.out.println(Long.toHexString(l)); // prints ffffffffcafebabe 

Lưu ý: trên các hệ thống dựa trên intel, byte là của vi được lưu trữ theo thứ tự ngược lại (ít nhất là byte quan trọng đầu tiên) vì kiến ​​trúc x86 lưu trữ các thực thể lớn hơn theo thứ tự này trong bộ nhớ. Rất nhiều phần mềm có nguồn gốc x86 cũng sử dụng nó ở định dạng tệp.