将Ada字符串转换为C Void *

时间:2012-02-13 02:59:08

标签: c string pointers ada

将Ada String“施放”到System.Adress的好方法是什么,这相当于在C中投放char*void*

我正在连接哪个C库。 C类型具有类型为void*的属性,并且库的用户通常将C字符串指向的地址指定为此值。 E.g:

struct my_type {
    void* value;
};

int main() {
    my_type t;
    t.value = "banana";
}

如何在Ada中实现等效,从Ada String开始?

我现在正在使用这种技术,但对我来说似乎很可疑。

declare
    str : constant String := "banana";
    data : constant char_array := To_C(str);
    mine : my_type;
begin
    mine.value := data(data'First)'Address;
end;

我对任何解决方案都很满意,甚至是Ada 2012。

1 个答案:

答案 0 :(得分:2)

您在评论中提到您正在使用void*“因为它应该能够获取任何地址;不只是一个字符串。“

那么,人们不得不问一般指针如何转化为Ada,特别是以利用打字和子打字功能的方式。我认为在这种情况下,“任何东西”都不能得到普遍解决;也就是说,如果你想保持构造的“灵活性”,你必须牺牲Ada提供的类型系统的优势。此外,我按原样提交,通常不可能可靠地用于“任何事情”。

我这样说是因为没有方法可以确定所包含的“任何东西”的长度。如果它是一个字符串,则长度来自指向地址,连续计数,直到第一个NUL字符(ASCII 0)。但是,如果它不是一个字符串,那么就没有确定长度的方法(我们怎么知道数组[1,2,3]或OBJECT的长度/大小)...所以我们没有办法确定甚至是“任何东西”的长度。

确定长度是编写稳定/安全代码的一个重要因素,因为如果不这样做,则会引发缓冲区溢出。


但是,如果您可以提供有关数据的一些信息,无论是通过参数还是更改my_struct,那么我们可以使用该信息来构建更好的类型转换。 (一般来说,关于类型的信息越多越好,因为你可以用以前的方式检查数据的有效性;或者更好的是,让编译器为你检查一下。)

Type Data_Type is Array( Positive Range <> ) of Interfaces.Unsigned_8;
  For Data_Type'Component_Size Use 8;


Function Some_Data( Stream : not null access Ada.Streams.Root_Stream_Type'Class; 
                    Length : In Positive ) Return Data_Type is
  begin
     Return Result : Data_Type(1..Length) do
        For Index in Result'Range loop
           Interfaces.Unsigned_8'Read(Stream, Result(Index));
        end Loop;
     End Return;
  end Some_Data;

您可以使用上述方法生成一个8位无符号整数数组,该数组将包含流中的数据。它概述了在一般情况下你必须做的事情,但是因为你正在使用C-imports,你可以做的是稍微修改一下,以便a)有一个Temp变量是一个数组与Result类似,但使用For Temp'Address Use [...]将其覆盖在my_type.value上,然后使用for循环将其复制出来。