【问题标题】:How do I import a C-function to Ada with pass-by-reference arguments?如何使用传递引用参数将 C 函数导入 Ada?
【发布时间】:2012-06-26 18:00:53
【问题描述】:

我有一个 C 函数 int func( int a, int* b) 需要在 Ada 95 中导入和使用。其中 C 函数通常在 C 中调用为 c = func(a, &b);

我一直将 C 函数导入 Ada,但一直避免使用通过引用参数传递的函数,但终于到了学习的时候了。

我想知道如何在 Ada 中声明这个函数,并且还想要一个简单的例子来使用它和显示的声明的变量(因为我对 Access 类型仍然有点模糊)。

谢谢大家!

【问题讨论】:

  • C 没有引用。这就是为什么你必须使用指针。它们是按值传递的。

标签: ada


【解决方案1】:

在 C 中,int* b 可能意味着很多东西。也许它实际上只是一个指向一个变量的指针,但它也可能是一个以int a 为长度的数组。此代码假定 int* b 实际上只是一个通过引用传递的值:

with Interfaces.C;

-- ...
package C renames Interfaces.C;

function Func (A : C.int; B : access C.int) return C.int;
pragma Import (Convention => C, Entity => Func,
               External_Name => "func");

-- ...

declare
   A : C.int := 42;
   B : aliased C.int := 23;
   C : C.int;
begin
   C := Func (A, B'Access);
   -- ...
end;

您可以在aliased 变量上使用'Access。只要您确定指针不会存储在 C 端并在变量 B 的生命周期结束后访问,这是安全的。 (如果 C 声明使用 const 关键字,您可以在 Ada 端使用 access constant,但这只是 Ada 2005。)

你也可以使用命名类型:

-- ...
type Int_Access is access C.int;
function Func (A : C.int; B : Int_Access) return C.int;
-- ...
C := Func (A, B'Unchecked_Access);
-- ...

现在我们需要使用'Unchecked_Access,因为Ada 通常不允许非本地访问类型(如Int_Access)引用局部变量。如果您知道 C 代码将如何处理指针(就像您应该做的那样),您可以使用命名类型来指定不应传递对局部变量的引用。

注意事项 1: 如果您有一个过程(在 C 语言中:一个返回 void 的函数),您可以在您的 Ada 中使用 in out 指定一个要通过引用传递的变量过程声明而不是access。这样,您根本不需要担心访问类型。和之前一样,需要确保指针没有存放在C端。

注意事项 2: 无论如何,记录类型和数组都是通过引用传递的 - 除非您指定 pragma Convention (C_Pass_By_Copy, Your_Type);。这是在 Ada 中包装 C 函数时的常见问题。

【讨论】:

  • 感谢您的出色回答,这也解决了我关于 Ada 和 C 之间的工作方式的其他一些问题。
  • C 接口函数的引用传递记录总是让我烦恼;与所有 C 类型一样,C 结构是通过副本传递的。默认情况下通过复制传递它们会更有意义,如果 C 函数需要一个指向结构的指针,则显式传递一个指针。
  • 我很确定C_Pass_By_Value 是特定于 GNAT 的(尽管如果其他 Ada 编译器采用了它,我不会感到惊讶)。
  • 我把名字弄错了。 pragma 的正确名称是C_Pass_By_Copy,它确实是 Ada 95 中 GNAT 特有的 pragma。它已添加到 Ada 2005 中。
【解决方案2】:

除了(和抄袭flyx)我还提供了一个完整的解决方案:

文件 c_thing.c

#include <stdio.h>

int foo (int a, int * b) {
  printf ("A:%d, B %d\n",a, *b);
}

文件 ada_main.adb

with Interfaces.C;

procedure Ada_Main is 

   package C renames Interfaces.C;

   function Func (A : C.int; B : access C.int) return C.int;
   pragma Import (Convention => C, Entity => Func,
                  External_Name => "foo");

   A : C.int := 42;
   B : aliased C.int := 23;
   R : C.int;

begin

   R := Func (A, B'Access);

end Ada_Main;

编译(linux):

gcc -c c_thing.c
gnatmake -c ada_main.adb
gnatbind ada_main.ali
gnatlink ada_main.ali c_thing.o

运行

./ada_main 
A:42, B 23

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-25
    • 1970-01-01
    • 2018-10-15
    • 2020-09-14
    • 1970-01-01
    • 1970-01-01
    • 2014-11-12
    • 1970-01-01
    相关资源
    最近更新 更多