2012-02-13 39 views
6

một cách tốt để "đúc" một Ada String đến một System.Adress đó sẽ là tương đương với đúc char* để void* trong C.Chuyển đổi Ada String để C Void *

Tôi interfacing mà một thư viện C là gì. Loại C có thuộc tính thuộc loại void* và người dùng thư viện thường chỉ định địa chỉ được trỏ tới bởi một chuỗi C làm giá trị này. Ví dụ:

struct my_type { 
    void* value; 
}; 

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

Làm cách nào để đạt được tương đương trong Ada, bắt đầu bằng chuỗi Ada?

Tôi đang sử dụng kỹ thuật này vào lúc này, nhưng có vẻ như cá đối với tôi.

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

tôi vẫn ổn với bất kỳ giải pháp, thậm chí Ada 2012.

+2

Bạn nên xem gói «Interfaces.C.Strings', chứa một loại' chars_ptr'. Hàm C bạn nhập phải sử dụng kiểu chars_ptr thay vì dấu *. – oenone

+2

Ngoài ra, hãy xem các giải pháp được đề xuất tại đây: http://en.wikibooks.org/wiki/Ada_Programming/Types/access#Where_is_void.2A.3F – oenone

+0

Thành viên 'void *' thuộc loại là 'void *' vì nó nên có thể lấy địa chỉ của bất cứ điều gì; không chỉ là một chuỗi.Đó là lý do tại sao 'g ++' tạo ra thông số Ada cho nó và sử dụng' System.Address'. Tôi thấy kỹ thuật này hiện đang hoạt động. Có lẽ đó là âm thanh? – Anthony

Trả lời

2

Bạn đề cập đến trong một chú thích mà bạn đang sử dụng void* “bởi vì nó sẽ có thể lấy địa chỉ của bất cứ điều gì; Không chỉ là một chuỗi. ”

Vì vậy, người ta phải hỏi làm thế nào để con trỏ chung dịch sang Ada, đặc biệt theo cách tận dụng các tính năng nhập và đánh máy phụ. Tôi sẽ đệ trình rằng “bất cứ điều gì”, trong bối cảnh này, không thể được giải quyết một cách tổng quát; đó là để nói, nếu bạn muốn duy trì tính linh hoạt của cấu trúc, bạn phải hy sinh những lợi thế mà Ada cung cấp với hệ thống kiểu của nó. Hơn nữa, tôi trình bày như là, nó thường không thể sử dụng đáng tin cậy cho "bất cứ điều gì".

Tôi nói điều này bởi vì không có phương pháp xác định ngay cả chiều dài của “bất cứ thứ gì”. Nếu đó là một chuỗi thì chiều dài là từ địa chỉ được chỉ định, đếm liên tục, cho đến ký tự NUL đầu tiên (ASCII 0) . Tuy nhiên, không có phương pháp xác định độ dài nếu nó không phải là một chuỗi (làm thế nào chúng ta biết chiều dài/kích thước của mảng [1,2,3] hoặc OBJECT) ... và vì vậy chúng tôi không có phương pháp để xác định ngay cả chiều dài của “bất cứ điều gì.”

Xác định độ dài là yếu tố quan trọng trong việc viết mã ổn định/an toàn, bởi vì nếu bạn không mời tràn bộ đệm.


Nhưng, để lại mà đi, nếu bạn có thể cung cấp một số thông tin về dữ liệu, cho dù qua tham số hoặc thay đổi my_struct, sau đó chúng ta có thể sử dụng thông tin đó để xây dựng một kiểu chuyển đổi tốt hơn. (Nói chung, bạn càng có nhiều thông tin về loại tốt hơn, vì sau đó bạn có thể kiểm tra tính hợp lệ của dữ liệu theo cách bạn không thể làm trước đó; hoặc tốt hơn, hãy kiểm tra trình biên dịch cho bạn.)

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; 

Bạn có thể sử dụng phần trên để tạo một mảng gồm các số nguyên không dấu 8 bit có chứa dữ liệu từ luồng. Nó phác thảo những gì bạn phải làm trong trường hợp chung, mặc dù kể từ khi bạn đang làm việc với C-nhập khẩu những gì bạn có thể làm là sửa đổi nó một chút để a) có một biến Temp mà là một mảng như Result nhưng sử dụng For Temp'Address Use [...] để phủ nó lên my_type.value và sau đó sử dụng vòng lặp for để sao chép nó.

Các vấn đề liên quan