复制C结构填充在Java中
-
22-07-2019 - |
题
根据此处,写作当C编译器将垫出值的结构为二进制文件。如该链路的例子说,写一个结构是这样,当:
struct {
char c;
int i;
} a;
为二进制文件,编译器将通常离开焦炭之间的未命名,未使用的孔和int字段,以确保INT字段被正确地对准。
怎么能予以创建二进制输出文件的精确副本(在C产生的),使用不同的语言(在我的情况下,爪哇)?
是否有在Java中输出是申请C填充自动方式?还是我必须要经过编译的文件,看看它是如何工作(编译器G ++的方式)。
解决方案
写入文件不仅在,而且在内存这是真实的。它是该结构在存储器填充,这导致填充显示出来的文件,如果该结构被写出逐字节的事实。
这是一般很难有把握地复制确切的填充方案,虽然我猜有些启发会让你很远。它帮助,如果您有结构声明,以供分析。
典型地,字段大于一个字符将被对齐,使得它们的起始结构内偏移量是它们的大小的倍数。这意味着short
s通常将是偶数偏移(由2整除,假设sizeof (short) == 2
),而double
s将在偏移被8整除,等等。
更新:这是这样的原因(也有字节排列顺序无关的原因),它通常是一个坏主意,倾倒整个结构出来的文件。这是更好地做场逐场,像这样:
put_char(out, a.c);
put_int(out, a.i);
假设put
函数只写所需的值的字节数,这将发出该结构的填充少版本到文件中,解决这个问题。另外,也可以通过相应地写入这些功能,以确保适当的,已知的字节顺序。
其他提示
不这样做,它是易碎的,并且将导致对齐和字节序的错误。
有关外部数据是要好得多以字节为单位显式地定义的格式和写显函数内部和外部的格式之间进行转换,使用移位和掩模(未工会!)。
是否有应用℃的自动方式 填充在Java中输出?还是我 经过编译器的文档 看看它是如何工作(编译器 克++的方式)。
都不是。相反,你明确指定数据/通信格式和实施规范,而不是依赖于C编译器的实现细节。你甚至不会得到从不同的C编译器输出相同。
有关的互操作性,看ByteBuffer类。
基本上,创建)一定大小的缓冲器,把(不同类型的在不同位置处的变量,然后调用阵列()结尾检索“原始”数据的表示:
ByteBuffer bb = ByteBuffer.allocate(8);
bb.order(ByteOrder.LITTLE_ENDIAN);
bb.put(0, someChar);
bb.put(4, someInteger);
byte[] rawBytes = bb.array();
但它是由你来制定出在哪里把padding--即多少字节位置之间跳跃。
有关读取由C写入的数据,则通常涡卷()的周围的一些字节数组的ByteBuffer你已经从文件中读取。
在情况下,它是有帮助的,我已经写了有关字节缓冲区。
的读出一种方便的方法/ Java编写C中的结构是使用javolution STRUCT类(参见的http:// WWW .javolution.org )。这不会帮助你自动填充/对齐你的数据,但它确实使在字节缓冲区更方便持有原始数据的工作。如果你不熟悉javolution,这是非常值得一看的还有很多其他很酷的东西在里面了。
此孔是可配置的,编译器有开关由1/2/4/8字节对齐结构。
所以,第一个问题是:你到底要哪个对准模拟
使用Java中,数据类型的大小是由语言规范定义的。例如,byte
类型是1个字节,short
是2个字节,等等。这和C,其中每个类型的大小是结构相关的。
因此,它会知道二进制文件的方式,以便能够读取该文件转换成Java格式是很重要的。
,可能有必要采取措施,以便可以肯定,字段是一个特定的尺寸,以考虑在编译器或体系结构的不同。对准的提及似乎表明,输出文件将取决于架构。
您可以尝试前子:
前子是用于建筑物的编解码器在比特流中压缩数据的Java库 声明(基于注解的)的方式。想想JAXB或休眠状态,但随后二进制 编码的数据。
,它可以处理大/小尾数二进制数据,对齐(填充)和各种数字类型沿着其它特征。这是一个非常好的图书馆,我非常喜欢它。
我0.02 $
我高度推荐协议缓冲区的正是这种问题。
据我了解,你说你不控制C程序的输出。你必须把它作为给定的。
所以你有阅读该文件对一些特定组结构,还是有在一般情况下解决这个问题?我的意思是,有人说,“这是由节目X创建的文件,你必须用Java读取它”的问题?还是他们期望你的Java程序读取C源代码,查找结构的定义,然后在Java中读它?
如果你有一个特定的文件阅读,这个问题是不是真的很困难。无论是通过审查的C编译器的规格或通过研究示例文件,找出其中填充的。然后,在Java端,读取该文件作为字节流,并建立你已知的值。基本上,我会写的一组功能,以从InputStream读取所需的字节数,并将其转化适当的数据类型。像:
int readInt(InputStream is,int len)
throws PrematureEndOfDataException
{
int n=0;
while (len-->0)
{
int i=is.read();
if (i==-1)
throw new PrematureEndOfDataException();
byte b=(byte) i;
n=(n<<8)+b;
}
return n;
}
您可以改变在C面的包装,以确保没有使用填充,或者你可以看看在十六进制编辑器生成的文件格式,让你用Java编写一个解析器将忽略填充字节。