在 Java 中实现 C 风格的位域
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12546106/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Implementing a C style bitfield in Java
提问by shadowisadog
I have a problem that I am a bit stuck on and I was informed by a colleague that this would be a good place to seek help.
我有一个问题,我有点被困住了,一位同事告诉我,这将是寻求帮助的好地方。
I am trying to implement a C style bitfield in Java. Here is a rough example (I do not have the actual code in front of me at this moment).
我正在尝试在 Java 中实现 C 风格的位域。这是一个粗略的例子(此时我面前没有实际的代码)。
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;
I have a good bit of similar style bitfields from legacy code. The reason that I need to come up with an equivalent method for Java is that I am working on code that will use Java to communicate with other legacy applications using UDP.
我有很多来自遗留代码的类似风格的位域。我需要为 Java 想出一个等效方法的原因是我正在编写将使用 Java 与使用 UDP 的其他遗留应用程序进行通信的代码。
I do not have the option of rewriting the code. I am aware that this approach is not portable, has endianness issues (and padding/alignment, ect), and could be done a better way if I were able to rewrite the code. Unfortunately I need an answer to this very specific problem. The system is closed and so I do not need to worry about every single possible combination of compilers/operating systems/ect.
我没有重写代码的选项。我知道这种方法不可移植,有字节序问题(和填充/对齐等),如果我能够重写代码,可以做得更好。不幸的是,我需要这个非常具体的问题的答案。系统是封闭的,所以我不需要担心编译器/操作系统/等的每一个可能的组合。
The approach of using a Java EnumSet will not work because I believe that will only allow for each value to be one bit. I need to be able to pack values with for instance the value of d occupying 10 bits.
使用 Java EnumSet 的方法将不起作用,因为我相信这将只允许每个值是一位。我需要能够将值打包,例如 d 的值占据 10 位。
I know about the Java Bitset but it has limitations. I am using an older version of Java, and so I do not have some of the newer Java Bitset methods (Namely the valueOf methods which would probably surely help).
我知道 Java Bitset 但它有局限性。我使用的是旧版本的 Java,所以我没有一些较新的 Java Bitset 方法(即可能肯定会有所帮助的 valueOf 方法)。
Does anyone have any ideas of how to make this as manageable as possible? I have over 10 bitfields that I need to implement for my communications.
有没有人知道如何使这尽可能易于管理?我需要为我的通信实现 10 多个位域。
Thank you for any help you can provide!
感谢您提供任何帮助!
采纳答案by Alexei Kaigorodov
Since UDP accepts only byte arrays, you can declare java class in any suitable way and the only critical step is to define serialization and deserialization methods:
由于 UDP 只接受字节数组,您可以以任何合适的方式声明 java 类,唯一关键的步骤是定义序列化和反序列化方法:
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;
}
}
回答by ant
Class Struct from Javolution library makes what you need (http://www.javolution.org/apidocs/index.html?javolution/io/Struct.html) See "Clock" example:
Javolution 库中的类 Struct 可以满足您的需求(http://www.javolution.org/apidocs/index.html?javolution/io/Struct.html)参见“时钟”示例:
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();
}
回答by shadowisadog
I ended up using a similar approach presented here: What is the most efficent way in Java to pack bits
我最终使用了此处介绍的类似方法:Java 中打包位的最有效方法是什么
And then I made a wrapper class that uses LinkedHashMapto store the individual bit field entries.
然后我制作了一个包装类,它使用LinkedHashMap来存储各个位字段条目。
Each field was implemented as a class that stores the number of bits and the value of the field. The name of the field is the key to the LinkedHashMap.
每个字段都被实现为一个类,用于存储位的数量和字段的值。该字段的名称是 LinkedHashMap 的键。
I added methods for starting and ending a structure, a method to add a bit field to the structure, and methods for getting and setting values based on keys.
我添加了开始和结束结构的方法、向结构添加位字段的方法以及基于键获取和设置值的方法。
My pack method iterates through the LinkedHashMap and puts the bits while keeping track of the bit offset (I just used an integer for this purpose).
我的 pack 方法遍历 LinkedHashMap 并放置位,同时跟踪位偏移量(为此我只使用了一个整数)。
The unpack method also iterates the LinkedHashMap and gets the bits, keeping track of the bit offset, and storing the values in the LinkedHashMap.
unpack 方法还迭代 LinkedHashMap 并获取位,跟踪位偏移量,并将值存储在 LinkedHashMap 中。
For convenience I wrote methods for packing the bit fields to integers, shorts, longs, and a byte. To convert between the byte array and the values I used a ByteBuffer and called the wrap method.
为方便起见,我编写了将位域打包成整数、短型、长型和字节的方法。为了在字节数组和值之间进行转换,我使用了 ByteBuffer 并调用了 wrap 方法。
I also wrote methods for unpacking a packed integer, short, long, or byte by first allocating the ByteBuffer for the number of bytes that the data type has (4 for integer, 2 for short, ect) and then calling the various put methods of the ByteBuffer. Once I had a byte array I was able to pass that to the unpack method.
我还编写了解包压缩整数、短、长或字节的方法,首先为数据类型具有的字节数分配 ByteBuffer(整数为 4,短为 2,等等),然后调用各种 put 方法字节缓冲区。一旦我有了一个字节数组,我就可以将它传递给 unpack 方法。
I went with this approach because I needed something self contained, that was easy to work with, and that was fairly easy for other people to follow... I know there are probably more elegant ways involving annotations or other things (I found JavaStruct but it didn't incorporate bit fields.)
我采用这种方法是因为我需要一些自包含的东西,它很容易使用,而且其他人也很容易遵循......我知道可能有更优雅的方法涉及注释或其他东西(我发现了 JavaStruct 但它没有包含位域。)
Packing and unpacking from various primitive data types enable me to read and write the results from a DataInputStream/DataOutputStream easier.
从各种原始数据类型打包和解包使我能够更轻松地从 DataInputStream/DataOutputStream 读取和写入结果。
I am sorry that I am unable to post the code for everyone to benefit from, so the above explanation will have to suffice. Hopefully it will help someone in a similar situation :).
很抱歉,我无法发布代码让大家受益,所以上面的解释就足够了。希望它能帮助处于类似情况的人:)。
回答by willglynn
Some cursory searching didn't reveal any libraries to make this easy, but you could always pack and unpack things by hand with bitwise operations:
一些粗略的搜索并没有显示任何库来简化这个过程,但是您总是可以通过按位操作手动打包和解包:
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);
}
// ...
}