将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。
答案 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循环将其复制出来。