如何处理Ada中的int **?

Dev*_*man 2 c ada ffi pass-by-reference memory-address

我正在尝试使用对它来自的C库的预先绑定来调用SDL_LoadWAV。SDL_LoadWAV只是SDL_LoadWAV_RW的包装:

function SDL_LoadWAV
 (file      : C.char_array;
  spec      : access SDL_AudioSpec;
  audio_buf : System.Address;
  audio_len : access Uint32) return access SDL_AudioSpec
is
begin
  return SDL_LoadWAV_RW
      (SDL_RWFromFile (file, C.To_C ("rb")),
       1,
       spec,
       audio_buf,
       audio_len);
end SDL_LoadWAV;
Run Code Online (Sandbox Code Playgroud)

这是C函数的原型:

SDL_AudioSpec* SDL_LoadWAV_RW(SDL_RWops*     src,
                          int            freesrc,
                          SDL_AudioSpec* spec,
                          Uint8**        audio_buf,
                          Uint32*        audio_len)
Run Code Online (Sandbox Code Playgroud)

(浏览此处获取更多信息)

现在您可以看到,它以Uint8 **的形式通过引用传递了一个Uint8(无符号8位整数)数组。这使我非常烦恼。这是适当的绑定:

function SDL_LoadWAV_RW
 (src       : access SDL_RWops;
  freesrc   : C.int;
  spec      : access SDL_AudioSpec;
  audio_buf : System.Address;
  audio_len : access Uint32) return access SDL_AudioSpec;
pragma Import (C, SDL_LoadWAV_RW, "SDL_LoadWAV_RW");
Run Code Online (Sandbox Code Playgroud)

如您所见,绑定将Uint8 **映射到System.Address。我尝试了一些技巧来将数据获取到想要的位置,但是似乎没有任何效果。现在,我的代码看起来像这样(其中包含一些自定义类型和异常):

type Music is new Resource with
record
    --Id : Integer; (Inherited from Resource)
    --Filename : Unbounded_String; (Inherited from Resource)
    --Archive_Name : Unbounded_String; (Inherited from Resource)
    --Zzl_Size : Integer; (Inherited from Resource)
    Audio : access SDL_AudioSpec_Access;
    Length : aliased Uint32;
    Buffer : System.Address;
    Position : Integer := 1;
end record;

overriding procedure Load(Mus : in out Music) is
    Double_Pointer : System.Address;
begin
    Log("Loading music " & To_Ada(Get_Audio_Filepath(Mus)));
    Audio_Load_Lock.Seize;
    if null = SDL_LoadWAV(Get_Audio_Filepath(Mus), Mus.Audio.all, Double_Pointer, Mus.Length'access) then
        raise Audio_Load_Failed with To_String(Mus.Filename) & "&Stack=" & Get_Call_Stack;
    end if;
    Log("Music length =" & Integer'Image(Integer(Mus.Length)));
    declare
        type Sample_Array is array(1..Mus.Length) of Uint8;
        Single_Pointer : System.Address;
        for Single_Pointer'address use Double_Pointer;
        pragma Import(Ada, Single_Pointer);
        Source : Sample_Array;
        for Source'address use Single_Pointer;
        pragma Import(Ada, Source); 
        Dest : Sample_Array;
        for Dest'address use Mus.Buffer;
        pragma Import(Ada, Dest);
    begin
        Dest := Source;
    end;
    Audio_Load_Lock.Release;
end Load;
Run Code Online (Sandbox Code Playgroud)

但是,就像我尝试过的所有其他内容一样,执行Load函数时,我得到一个PROGRAM_ERROR / EXCEPTION_ACCESS_VIOLATION。

谁能弄清楚我需要如何处理此System.Address?谢谢!

Sim*_*ght 5

说的定义SDL_LoadWAV_RW

如果成功调用此函数,则该函数返回指向SDL_AudioSpec结构的指针,该结构填充有波形源数据的音频数据格式。audio_buf用指向分配的包含音频数据的缓冲区的指针填充,而audio_len用该音频缓冲区的长度(以字节为单位)填充。

这意味着被调用函数分配所需的内存并填充它,然后返回指向分配的内存及其长度的指针。

因此,您提供的绑定不是很好的Ada。

audio_buf应该是out字节数组audio_lenout参数,是的参数Uint32

作为演示,使用此C:

#include <stdlib.h>
void get_data (char **buf, int *len)
{
  *len = 10;
  *buf = malloc(*len);
  for (int j = 0; j < *len; j++) {
    (*buf)[j] = j;
  }
}
Run Code Online (Sandbox Code Playgroud)

这个阿达

type Raw is array (Interfaces.Unsigned_32) of Interfaces.Unsigned_8
with Convention => C;
Run Code Online (Sandbox Code Playgroud)

定义一个数组类型(如果我们实际声明一个数组类型,它将占用2 ^ 32-1个字节!),

type Raw_P is access all Raw
with Convention => C, Storage_Size => 0;
Run Code Online (Sandbox Code Playgroud)

定义指向此类数组的指针。将存储大小限制为0意味着我们不能说new Raw_P

放在一起,

with Ada.Text_IO; use Ada.Text_IO;
with Interfaces;
procedure Demo is
   type Raw is array (Interfaces.Unsigned_32) of Interfaces.Unsigned_8
   with Convention => C;

   type Raw_P is access all Raw
   with Convention => C, Storage_Size => 0;

   procedure Get_Data (In_Buffer : out Raw_P;
                       Length    : out Interfaces.Unsigned_32)
   with
     Import,
     Convention    => C,
     External_Name => "get_data";

   Allocated : Raw_P;
   Length    : Interfaces.Unsigned_32;

   use type Interfaces.Unsigned_32;
begin
   Get_Data (In_Buffer => Allocated,
             Length    => Length);
   for J in 0 .. Length - 1 loop
      Put (Allocated (J)'Image);
   end loop;
   New_Line;
end Demo;
Run Code Online (Sandbox Code Playgroud)

给出一个程序,在运行时会导致

$ ./demo
 0 1 2 3 4 5 6 7 8 9
$
Run Code Online (Sandbox Code Playgroud)

----

认识到您可能会坚持

audio_buf : System.Address;
Run Code Online (Sandbox Code Playgroud)

您可以定义(或使用,如果已经定义的话)类似my的内容RawRaw_P然后说

procedure Get_Data (In_Buffer : System.Address;
                    Length    : out Interfaces.Unsigned_32)
with
  Import,
  Convention    => C,
  External_Name => "get_data";
Run Code Online (Sandbox Code Playgroud)

然后使用

Get_Data (In_Buffer => Allocated'Address,
          Length    => Length);
Run Code Online (Sandbox Code Playgroud)