【问题标题】:How can I return a string allocated in C to Ada and free it in Ada?如何将 C 中分配的字符串返回给 Ada 并在 Ada 中释放它?
【发布时间】:2020-01-29 00:25:14
【问题描述】:

这是this question的倒数。

我在 C 函数(特别是 cJSON 库)中分配了一个字符串,我想将它作为输出参数返回给 Ada 调用者,并从 Ada 中释放该字符串。

C 接口如下所示:

typedef struct
{
    int f1;
    int f2;
    // ...
} A;

int Dump_Record(const A& rec, char** outstr);

Dump_Record 函数将 outstr 设置为cJSON_Print 返回的值,它通过malloc 分配一个字符串。

应如何指定 Ada 绑定以及如何检索输出字符串并在 Ada 中正确释放它?

【问题讨论】:

  • 如果你想释放(释放)cJSON分配的对象,那么你应该导入并使用cJSON的释放函数cJSON_free。我强烈建议不要混合不同软件组件的分配器/释放器功能,因为它们可能不共享相同的存储机制。分配器/释放器函数总是成对出现,应该这样使用。

标签: c ada


【解决方案1】:

以下显示了用于返回 char ** 作为返回类型和 out Ada 参数的 Ada、C 和 GPR 文件。

with Ada.Text_IO; use Ada.Text_IO;
with Interfaces.C.Strings; use Interfaces.C.Strings;

procedure Str is
   function Get_Str return chars_ptr with
     Import => True,
     Convention => C,
     External_Name => "get_str";

   procedure Get_Str (Str : in out chars_ptr) with
     Import => True,
     Convention => C,
     External_Name => "get_str2";

   Str  : chars_ptr := Get_Str;
   Str2 : chars_ptr := Null_Ptr;
begin
   Get_Str (Str2);

   Put ("==> " & Value (Str));
   Put ("==> " & Value (Str2));

   Free (Str);
   Free (Str2);
end Str;
#include <malloc.h>
#include <string.h>

const char *str  = "Hello, Ada\n";
const char *str2 = "This is another C string!\n";

// As a return type.
const char *get_str (void) {
    char *ptr = malloc (strlen (str) + 1);

    strcpy (ptr, str);

    return ptr;
}

// As a return / out parameter.
void get_str2 (char **ptr) {
    *ptr = malloc (strlen (str2) + 1);

    strcpy (*ptr, str2);
}
project Str is
   for Languages use ("C", "Ada");
   for Source_Dirs use (".");
   for Exec_Dir use ".";
   for Main use ("str.adb");
end Str;

使用gprbuild -P str编译。

所以要在 Ada 中实现你的功能:

package C renames Interfaces.C;

type A is
   record
      F1, F2 : C.int;
   end record with
     Convention => C;

   function Dump_Record (Rec : aliased A; Out_Str : out chars_ptr) return C.int with
     Import => True,
     Convention => C,
     External_Name => "Dump_Record";

显然,需要为 Rec 参数设置别名,以便编译器知道它是 C 中的引用,并且不会在其他地方重新分配它,即辅助堆栈。

【讨论】:

  • 我不确定,但是在给定RM B.3.1 (55) 的情况下使用Free 是否可以接受?
  • @DeeDee,“错误”意味着它可能会起作用 - 但话又说回来,它可能不会。或者它可能适用于此版本的编译器,但不适用于其他版本。而且“工作”有点不确定,因为我们正在这里玩(碰碰我们的手臂)记忆舞台。
  • 它将与 GNAT 一起使用,因为 GNAT 将 malloc/free 用于 new/unchecked_deallocation,这将与 C 应用程序匹配。如果另一个编译器不使用 malloc/free,那么这可能不起作用。
  • 为了保证它有效,你应该使用procedure Free_Chars (Ptr : chars_ptr) with Import =&gt; True, Convention =&gt; C, External_Name =&gt; "free";
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-27
  • 1970-01-01
  • 1970-01-01
  • 2020-02-07
  • 1970-01-01
相关资源
最近更新 更多