Ada向C发送字节缓冲区

3

我遇到了一些与从Ada接口到C的问题。 特别是,我有这个ada声明:

type Byte is mod 256; pragma Convention (C, Byte);
type ByteStream is array (Interfaces.C.size_t range <>) of Byte;
    pragma Convention (C, ByteStream);
type VoidPointer is access all ByteStream;
type ByteBuffer is
    record
        data : VoidPointer;
        size : Interfaces.C.size_t;
    end record;
pragma Convention (C, ByteBuffer);
procedure Free is new Ada.Unchecked_Deallocation (ByteStream, VoidPointer);

以及这个C声明:

struct ByteBuffer {
    unsigned char *data;
    size_t size;
};

还有这个ada导入:

function My_Function (
    data : in ByteBuffer)
    return Interfaces.C.int;
pragma Import (C, My_Function, "my_function");

而这个C声明:
int my_function(struct ByteBuffer data);

然而,当我调试我的代码时,在ada端发现大小为110,在c端却是0x7fffffffe750。为什么我的size_t被破坏了?(注意:数据本身也被破坏了,但希望修复一个问题会修复另一个问题)。


可能是C结构的填充问题。不确定Ada如何处理其记录。或者是您代码中的一些错误。 - Eugene Sh.
我本以为 pragma Convention (C, ByteBuffer); 可以解决这个问题。也许我还需要在 C 端指定一些东西? - LambdaBeta
填充是编译器特定的。关于它没有"C约定"。 - Eugene Sh.
2个回答

3
在Ada中,“in”参数可以使用引用或副本,但这取决于编译器/结构大小。
为了强制双方使用指针(在这里最简单的方法),您可以这样做:
在Ada侧:
function My_Function (
    data : access ByteBuffer)
    return Interfaces.C.int;
pragma Import (C, My_Function, "my_function");

C方面的内容:

int my_function(const struct ByteBuffer *data);

由于 ByteBuffer 是一个受限制的数组,所以还需要传递另一个信息:边界指针(整个指针是“fat”指针)。您可以在C端通过执行以下操作来“跳过”它:

struct ByteBuffer {
    unsigned char *data;
    void *skipit;  // ignore this value
    size_t size;
};

如果要强制Ada按复制方式传递,您可以在类型声明后使用pragma Convention(C_Pass_By_Copy,ByteBuffer)(在Ada端)。


我刚试了一下。现在bytebuffer里的数据是正确的(YAY!),但size_t仍然混乱。:( 看起来结构可能确实像Eugene所说的那样填充了。我可能需要手动拆分缓冲区及其大小。 - LambdaBeta
太好了,那确实是问题所在。出于好奇,如果skipit正在存储边界,是否有一种方法可以直接在C端访问它们? - LambdaBeta
可以做到。不确定第二个指针的价值。请在调试器中检查差异,它可能是数组的末尾。 - Jean-François Fabre
如果您需要去除填充,您可以始终使用“Size”属性。 - darkestkhan

0

Ada的无界字符串具有编译器相关的数据映射。在我使用的编译器中,我已经检查过它以某些东西(如标记)开头,表示字符串的大小,然后是“正常”的字节数组。当您将缓冲区从C传递到Ada时,后者将从您的C数组的第一个元素中获取无界数组的长度。 我不知道为什么您需要示例,但如果我假设您要指向已创建数据的数组,则可以将ByteStream声明为固定长度数组(假设与您的最大大小一样大),因为您将使用“size”参数来管理实际大小。 换句话说,在Ada中,您的ByteBuffer记录的“size”参数进入指向的无界字符串结构并且可以使用'Length属性提取,这是没有意义的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接