我可以从Unbounded_String获得chars_ptr,只需最少的复制吗?

时间:2013-10-01 08:51:25

标签: c string ada

我有Ada.Strings.Unbounded.Unbounded_String,我想传递给C函数,该函数在Ada中使用char *Interfaces.C.chars_ptr

我当前的实现涉及将无界字符串复制到固定字符串,然后将固定字符串复制到chars_ptr

F_String : String := To_String (UB_String);
C_String : chars_ptr := New_String (F_String);

请注意,这会复制两次,最后我只会调用

Imported_Function (C_String);
Free (C_String);

弃用F_String

我是否可以使用最少的复制实现所需的行为(将Unbounded String中保存的字符串传递给导入的C函数)?理想情况下,将UB_String的内部缓冲区直接传递给函数会很酷,但这可能不是可移植的。我是否至少可以在不需要中间固定字符串的情况下实现相同的行为?

我看到GNAT有内部包Ada.Strings.Unbounded.Aux,它允许您访问Unbounded String的内部缓冲区,但这不可移植,并且可能在GNAT版本之间中断。

2 个答案:

答案 0 :(得分:1)

ada中的字符串操作是一种痛苦,除了首先避免使用无界字符串(可能只在记录中需要字符串字段时才使用它们),你可以做的事情并不多。

with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Interfaces.C; use Interfaces.C;
...
procedure Imported_Function(Item : in access Interfaces.C.Char);
pragma Import(C, Imported_Function, "...");
Item : aliased Interfaces.C.Char_Array := To_C(To_String(UB_String)); -- no need to free
begin
  Imported_Function(Item(Item'first)'access);
  ... 

答案 1 :(得分:1)

简短且令人失望的答案是:不是以便携方式。

但是你有一些选择:

  1. 删除可移植性并挂钩到编译器随附的标准库的特定版本的内部。
  2. 编写自己的字符串类型,符合您的要求。
  3. 接受额外的副本,直到您发现它是您的应用程序的问题。
  4. 广告。 1:

    好像你已经找到了如何挂钩GNAT Ada.Strings.Unbounded包。

    广告。 2:

    考虑如何“无限制”你的字符串类型真的必须。你知道长度上几乎是一定的上限吗?在最糟糕的情况下,为每个字符串分配两倍的VM页面是不合理的吗?如果没有分配足够的内存,什么是可接受的操作?失败?分配更多和复制?创建链接列表然后必须为“导出”目的制作副本?在Ada中创建自定义类型并不是那么困难,所以请考虑一下,如果您有一些特殊要求(就像在这种情况下听起来那样)。