簡體   English   中英

如何在 Ada 中處理 int**?

[英]How do I handle an int** in Ada?

我正在嘗試使用與它來自的 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;

這是C中的function的原型:

SDL_AudioSpec* SDL_LoadWAV_RW(SDL_RWops*     src,
                          int            freesrc,
                          SDL_AudioSpec* spec,
                          Uint8**        audio_buf,
                          Uint32*        audio_len)

(瀏覽此處獲取更多信息)

現在您可以看到,它通過引用以 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");

如您所見,綁定將 Uint8** 映射到 System.Address。 我已經嘗試了一些技巧來獲取我想要的數據到 go,但似乎沒有任何效果。 現在,我的代碼看起來像這樣(它有一些自定義類型和異常):

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;

但是,就像我嘗試過的或多或少的其他所有事情一樣,當執行 Load function 時,我得到了 PROGRAM_ERROR/EXCEPTION_ACCESS_VIOLATION。

誰能弄清楚我需要如何處理這個 System.Address? 謝謝!

SDL_LoadWAV_RW的定義

這個function如果調用成功,則返回一個指向SDL_AudioSpec結構的指針,該結構填充了波源數據的音頻數據格式。 audio_buf 填充了指向包含音頻數據的已分配緩沖區的指針,而 audio_len 填充了該音頻緩沖區的長度(以字節為單位)。

這意味着被調用的 function 分配所需的 memory 並填充它,然后返回指向分配的 memory 的指針及其長度。

所以你得到的綁定不是很好,艾達。

audio_buf應該是字節數組的out參數, Uint32應該是audio_lenout參數。

作為演示,使用此 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;
  }
}

這個阿達

type Raw is array (Interfaces.Unsigned_32) of Interfaces.Unsigned_8
with Convention => C;

定義一個數組類型(如果我們實際聲明一個,它將占用 2^32-1 個字節),並且這個

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

定義了一個指向這樣一個數組的指針。 將存儲大小限制為 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;

給出一個程序,它在運行時會導致

$ ./demo
 0 1 2 3 4 5 6 7 8 9
$

----

認識到你可能被困在

audio_buf : System.Address;

你可以定義(或使用,如果已經定義)像我的RawRaw_P和說

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

然后使用

Get_Data (In_Buffer => Allocated'Address,
          Length    => Length);

SDL_LoadWAV 將在您提供的位置寫入一個指針(指向由 SDL 分配的新緩沖區),即未初始化變量 Double_Pointer 的值,它是一個隨機地址 -> kaboom!

在調用 SDL_LoadWAV 之前,您需要具備以下條件:

Double_Pointer := SDL_Buffer'Address;

其中SDL_Buffer以前是這樣定義的:

type Buffer_Access_Type is access all Buffer_Type;
SDL_Buffer: Buffer_Access_Type;

根據 API,您需要稍后使用SDL_FreeWAV SDL_Buffer

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM