有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

在Java中复制C结构填充

根据here,C编译器在将结构写入二进制文件时将填充值。正如链接中的示例所示,在编写这样的结构时:

struct {
 char c;
 int i;
} a;

对于二进制文件,编译器通常会在char和int字段之间留下一个未命名、未使用的孔,以确保int字段正确对齐

如何使用不同的语言(在我的例子中是Java)创建二进制输出文件(用C生成)的精确副本

是否有一种在Java输出中自动应用C填充的方法?或者我必须通过编译器文档来了解它是如何工作的(顺便说一下,编译器是g++的)


共 (6) 个答案

  1. # 1 楼答案

    这个洞是可配置的,编译器有开关将结构对齐1/2/4/8字节

    所以第一个问题是:你到底想模拟哪条路线

  2. # 2 楼答案

    不仅在写入文件时如此,在内存中也是如此。事实上,结构在内存中被填充,如果结构被逐字节写入,那么填充就会出现在文件中

    一般来说,很难确定地复制精确的填充方案,尽管我猜一些启发式方法会让你走得很远。如果您有用于分析的struct声明,这会有所帮助

    通常,大于一个字符的字段将被对齐,以便其在结构中的起始偏移量是其大小的倍数。这意味着shorts通常位于偶数偏移量上(假设sizeof (short) == 2,可被2整除),而doubles位于可被8整除的偏移量上,依此类推

    更新:出于这样的原因(以及与endianness有关的原因),将整个结构转储到文件中通常是个坏主意。最好一个接一个地做,就像这样:

    put_char(out, a.c);
    put_int(out, a.i);
    

    假设put函数只写入值所需的字节,这将向文件发出结构的无填充版本,从而解决问题。通过相应地编写这些函数,也可以确保正确的已知字节顺序

  3. # 3 楼答案

    不要这样做,它很脆弱,会导致对齐和端点错误

    对于外部数据,最好用字节显式定义格式,并编写显式函数,使用移位和掩码(而不是并集!)在内部和外部格式之间进行转换

  4. # 4 楼答案

    要了解互操作性,请查看ByteBuffer类

    本质上,您创建一个特定大小的缓冲区,将不同类型的()变量放在不同的位置,然后在末尾调用array()来检索“原始”数据表示:

    ByteBuffer bb = ByteBuffer.allocate(8);
    bb.order(ByteOrder.LITTLE_ENDIAN);
    bb.put(0, someChar);
    bb.put(4, someInteger);
    byte[] rawBytes = bb.array();
    

    但这取决于你决定在哪里放置填充——也就是说,在不同的位置之间要跳过多少字节

    为了读取从C中写入的数据,通常需要在从文件中读取的某个字节数组周围使用字节缓冲符

    如果有帮助的话,我已经写了更多关于ByteBuffer

  5. # 5 楼答案

    Is there an automatic way to apply C padding in Java output? Or do I have to go through compiler documentation to see how it works (the compiler is g++ by the way).

    都不是。相反,您可以显式地指定数据/通信格式并实现该规范,而不是依赖于C编译器的实现细节。你甚至不会从不同的C编译器中得到相同的输出

  6. # 6 楼答案

    在Java中读/写C结构的一种简便方法是使用javolution Struct类(参见http://www.javolution.org)。这不会帮助您自动填充/对齐数据,但它确实使处理字节缓冲区中的原始数据更加方便。如果你不熟悉javolution,那就值得一看,因为里面还有很多其他很酷的东西