Преобразование строки Ada в C Void * - PullRequest
6 голосов
/ 13 февраля 2012

Что является хорошим способом "кастовать" Аду String в System.Adress, что было бы эквивалентно приведению char* к void* в С.

Я взаимодействую с библиотекой Си. Тип C имеет свойство типа void*, и пользователи библиотеки обычно присваивают адрес, на который указывает C-строка, в качестве этого значения. Например:

struct my_type {
    void* value;
};

int main() {
    my_type t;
    t.value = "banana";
}

Как мне получить эквивалент в Аде, начиная со строки Ады?

Сейчас я использую эту технику, но она мне кажется подозрительной.

declare
    str : constant String := "banana";
    data : constant char_array := To_C(str);
    mine : my_type;
begin
    mine.value := data(data'First)'Address;
end;

Я в порядке с любым решением, даже Ada 2012.

1 Ответ

2 голосов
/ 15 февраля 2012

Вы упоминаете в комментарии, что используете void* «потому что он должен быть в состоянии взять адрес чего угодно;не просто строка. ”

Итак, нужно спросить, как общий указатель переводится в Аду, особенно таким образом, чтобы воспользоваться преимуществами функций ввода и подтипа.Я бы сказал, что «что-нибудь» в этом контексте не может быть решено вообще;то есть, если вы хотите сохранить «гибкость» конструкции, вы должны пожертвовать преимуществами, которые Ada обеспечивает своей системой типов.Кроме того, я утверждаю, что представленный как есть, как правило, невозможно надежно использовать для «чего-либо».

Я говорю это, потому что нет способа определить даже длину содержащегося «чего-либо». Если этострока, длина которой начинается от указанного адреса, считая последовательно, до первого символа NUL (ASCII 0).Однако нет способа определить длину, если она не является строкой (как мы узнаем длину / размер массива [1,2,3] или OBJECT) ... и поэтому у нас нет метода для определения дажедлина «всего».

Определение длины является важным фактором при написании стабильного / безопасного кода, потому что, если вы этого не делаете, вы вызываете переполнение буфера.


НоЕсли не включать, если вы можете предоставить некоторую информацию о данных, будь то с помощью параметра или изменения my_struct, то мы можем использовать эту информацию для создания лучшего преобразования типов.(В общем, чем больше у вас информации о типе, тем лучше, потому что вы можете проверить достоверность данных так, как раньше не могли; или еще лучше, чтобы компилятор проверил это за вас.)

Type Data_Type is Array( Positive Range <> ) of Interfaces.Unsigned_8;
  For Data_Type'Component_Size Use 8;


Function Some_Data( Stream : not null access Ada.Streams.Root_Stream_Type'Class; 
                    Length : In Positive ) Return Data_Type is
  begin
     Return Result : Data_Type(1..Length) do
        For Index in Result'Range loop
           Interfaces.Unsigned_8'Read(Stream, Result(Index));
        end Loop;
     End Return;
  end Some_Data;

Вы можете использовать вышеупомянутое, чтобы сгенерировать массив 8-разрядных целых чисел без знака, который будет содержать данные из потока.Он описывает, что вам нужно сделать в общем случае, хотя, поскольку вы работаете с C-import, вы можете немного изменить его, чтобы: а) была переменная Temp, представляющая собой массив типа Result но используйте For Temp'Address Use [...], чтобы наложить его на my_type.value, а затем используйте цикл for, чтобы скопировать его.

...