2012-09-22 24 views
6

Tôi gặp vấn đề khi tôi bị mắc kẹt và tôi được một đồng nghiệp thông báo rằng đây sẽ là một nơi tốt để tìm sự giúp đỡ.Thực hiện một bitfield kiểu C trong Java

Tôi đang cố triển khai bitfield kiểu C trong Java. Đây là một ví dụ sơ bộ (tôi không có mã thực sự trước mặt tôi tại thời điểm này).

typedef union 
{ 
    typedef struct 
    { 
    unsigned short a :1; 
    unsigned short b :1; 
    unsigned short c :2; 
    unsigned short d :10; 
    } bitfield; 

    unsigned short bitmap; 
}example_bitfield; 

Tôi có một bit bit kiểu bit tương tự từ mã cũ. Lý do tôi cần đưa ra một phương thức tương đương cho Java là tôi đang làm việc trên mã sẽ sử dụng Java để giao tiếp với các ứng dụng kế thừa khác bằng cách sử dụng UDP.

Tôi không có tùy chọn viết lại mã. Tôi biết rằng cách tiếp cận này không phải là di động, có các vấn đề về endianness (và padding/alignment, ect), và có thể được thực hiện một cách tốt hơn nếu tôi có thể viết lại mã. Thật không may tôi cần một câu trả lời cho vấn đề rất cụ thể này. Hệ thống đã bị đóng và vì vậy tôi không cần phải lo lắng về mọi sự kết hợp có thể có của các trình biên dịch/hệ điều hành/ect.

Cách tiếp cận sử dụng Java EnumSet sẽ không hoạt động vì tôi tin rằng sẽ chỉ cho phép mỗi giá trị có một bit. Tôi cần để có thể đóng gói các giá trị với ví dụ giá trị của d chiếm 10 bit.

Tôi biết về Java Bitset nhưng nó có giới hạn. Tôi đang sử dụng một phiên bản Java cũ hơn, và vì vậy tôi không có một số phương thức Java Bitset mới hơn (Cụ thể là các phương thức valueOf chắc chắn sẽ giúp ích).

Có ai có bất kỳ ý tưởng nào về cách làm cho điều này dễ quản lý nhất có thể không? Tôi có trên 10 bitfield mà tôi cần phải thực hiện cho các liên lạc của mình.

Cảm ơn bạn đã được trợ giúp bạn có thể cung cấp!

+1

Lưu ý rằng ví dụ ban đầu của bạn thực sự là một hành vi không xác định. – oldrinb

+0

Vì bạn có phiên bản Java cũ và có giới hạn, bạn có thể cho chúng tôi biết nó là gì không? –

+0

Đây là Java SE 6. Về mặt kỹ thuật, các bitfield đang được biên dịch bằng trình biên dịch C++. Tôi tin rằng C++ đã thêm hỗ trợ cho việc sử dụng các loại khác với số nguyên. Nếu nó không xác định, tôi có thể chấp nhận điều đó ... Tôi không có tùy chọn để sửa nó, và bất cứ hành vi nào nó hiện đang làm là những gì tôi phải cạnh tranh. – shadowisadog

Trả lời

4

Kể từ UDP chỉ chấp nhận mảng byte, bạn có thể khai báo java lớp trong bất kỳ cách nào phù hợp và các bước quan trọng duy nhất là để xác định serialization và deserialization phương pháp:

class example_bitfield { 
    byte a; 
    byte b; 
    byte c; 
    short d; 

    public void fromArray(byte[] m) { 
    byte b0=m[0]; 
    byte b1=m[1]; 
    a=b0>>>7; 
    b=(b0>>6)&1; 
    c=(b0>>4)&3; 
    d=(b0&0xF<<6)|(b1>>>2); 
    } 
    public void toArray(byte[] m) { 
    m[0]=(a<<7)|(b<<6)|(c<<4)|(d>>>6); 
    m[1]=(d&0x3F)<<2; 
    } 
} 
+0

Có điểm tốt và cảm ơn bạn đã phản hồi. Tôi vẫn hy vọng cho một giải pháp tổng quát hơn bởi vì tôi có rất nhiều bitfield để giải quyết. Làm mỗi cách thủ công có vẻ như nó sẽ là một trải nghiệm rất đau đớn. – shadowisadog

+0

Hãy cẩn thận rằng bạn không đặt bất kỳ giá trị thành viên nào ở bên ngoài phạm vi hợp lệ của chúng hoặc thêm một số mặt nạ vào tuần tự hóa; ngay bây giờ, việc tuần tự hóa 'a = 2' sẽ dẫn đến' a = 0', 'b = 1'. – willglynn

2

Một số tìm kiếm lướt qua không tiết lộ bất kỳ thư viện để thực hiện điều này dễ dàng, nhưng bạn luôn có thể đóng gói và giải nén mọi thứ bằng tay với các hoạt động Bitwise:

class ExampleBitfield { 
    int bitfield;  // actually 16 bits 

    public int getBitfield() { 
     return bitfield; 
    } 
    public void setBitfield(int bitfield) { 
     this.bitfield = bitfield & 0xffff; 
    } 

    // lowest bit 
    public int getA() { 
     return (bitfield >> 0) & 0x01; 
    } 
    public int setA(int a) { 
     return (bitfield & ~0x01) | ((a & 0x01) << 0); 
    } 

    // second lowest bit 
    public int getB() { 
     return (bitfield >> 1) & 0x01; 
    } 
    public int setB(int b) { 
     return (bitfield & ~0x02) | ((b & 0x01) << 1); 
    } 

    // ... 
} 
+0

Cảm ơn bạn willglynn. Tôi đã biết rằng điều này là có thể, tuy nhiên với số lượng bitfields mà tôi phải xử lý, tôi đã sợ cách tiếp cận này sẽ khó quản lý và có thể khó khăn để gỡ lỗi. Tôi đã tìm thấy [link] này (http://stackoverflow.com/questions/7604653/what-is-the-most-efficient-way-in-java-to-pack-bits-into-byte-and- read-it-back) Điều này có vẻ tương tự như cách tiếp cận của bạn nhưng có lẽ hơi chung chung hơn. – shadowisadog

3

tôi đã kết thúc bằng một cách tiếp cận tương tự như trình bày ở đây: What is the most efficent way in Java to pack bits

Và sau đó tôi đã thực hiện một lớp bao bọc sử dụng LinkedHashMap để lưu trữ các mục nhập trường bit riêng lẻ.

Mỗi trường được triển khai dưới dạng lớp lưu trữ số bit và giá trị của trường. Tên của trường là khóa cho LinkedHashMap.

Tôi đã thêm các phương thức để bắt đầu và kết thúc cấu trúc, một phương pháp để thêm trường bit vào cấu trúc và phương thức nhận và đặt giá trị dựa trên khóa.

Phương thức gói của tôi lặp lại thông qua LinkedHashMap và đặt các bit trong khi theo dõi bù đắp bit (Tôi chỉ sử dụng một số nguyên cho mục đích này).

Phương thức giải nén cũng lặp lại LinkedHashMap và nhận các bit, theo dõi bù đắp bit và lưu trữ các giá trị trong LinkedHashMap.

Để thuận tiện, tôi đã viết các phương pháp để đóng gói các trường bit thành số nguyên, quần short, độ dài và byte. Để chuyển đổi giữa mảng byte và các giá trị tôi đã sử dụng một ByteBuffer và được gọi là phương thức bọc.

Tôi cũng đã viết phương pháp để giải nén một số nguyên, ngắn, dài hoặc byte bằng cách phân bổ ByteBuffer đầu tiên cho số byte mà kiểu dữ liệu có (4 cho số nguyên, 2 cho ngắn, vv) và sau đó gọi phương pháp đặt khác nhau của ByteBuffer. Một khi tôi đã có một mảng byte tôi đã có thể vượt qua đó để giải nén phương pháp.

Tôi đã đi theo phương pháp này vì tôi cần thứ gì đó tự chứa, dễ làm việc và điều đó khá dễ dàng cho những người khác theo dõi ... Tôi biết có lẽ có nhiều cách thanh lịch hơn liên quan đến chú thích hoặc những thứ khác (Tôi đã tìm thấy JavaStruct nhưng nó không kết hợp các trường bit.)

Đóng gói và giải nén từ các kiểu dữ liệu nguyên thủy khác nhau cho phép tôi đọc và ghi kết quả từ một DataInputStream/DataOutputStream dễ dàng hơn.

Tôi rất tiếc vì tôi không thể đăng mã để mọi người được hưởng lợi, vì vậy lời giải thích ở trên sẽ phải đủ. Hy vọng rằng nó sẽ giúp ai đó trong một tình huống tương tự :).

2

Lớp Struct từ thư viện Javolution làm những gì bạn cần (http://www.javolution.org/apidocs/index.html?javolution/io/Struct.html) Xem "Clock" Ví dụ:

import java.nio.ByteBuffer; 
class Clock extends Struct { // Hardware clock mapped to memory. 
    Unsigned16 seconds = new Unsigned16(5); // unsigned short seconds:5 
    Unsigned16 minutes = new Unsigned16(5); // unsigned short minutes:5 
    Unsigned16 hours = new Unsigned16(4); // unsigned short hours:4 
    Clock() { 
     setByteBuffer(Clock.nativeBuffer(), 0); 
    } 
    private static native ByteBuffer nativeBuffer(); 
}