2012-02-13 17 views
6

cosa è un buon modo per "cast" di Ada String ad un System.Adress che sarebbe equivalente a lanciare char* a void* in C.Conversione Ada String in C Void *

sto interfacciamento che una libreria C. Un tipo C ha una proprietà che è di tipo void* e gli utenti della libreria in genere assegnano l'indirizzo indicato da una stringa C come questo valore. Per esempio:

struct my_type { 
    void* value; 
}; 

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

Come posso ottenere l'equivalente in Ada, a partire da una stringa Ada?

Sto usando questa tecnica al momento, ma mi sembra strano.

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

Sto bene con qualsiasi soluzione, anche Ada 2012.

+2

Si dovrebbe dare un'occhiata al pacchetto 'Interfaces.C.Strings', che contiene un tipo' chars_ptr'. La funzione C che importi dovrebbe usare il tipo chars_ptr al posto del void *. – oenone

+2

Inoltre, guarda le soluzioni suggerite qui: http://en.wikibooks.org/wiki/Ada_Programming/Types/access#Where_is_void.2A.3F – oenone

+0

Il membro 'void *' del tipo è 'void *' perché dovrebbe essere in grado di prendere l'indirizzo di qualsiasi cosa; non solo una stringa.Ecco perché 'g ++' ha generato la specifica Ada per esso e ha usato 'System.Address'. Trovo che la tecnica al momento funzioni attualmente. Forse è suono? – Anthony

risposta

2

Lei parla in un commento che si sta utilizzando void* “perché dovrebbe essere in grado di prendere l'indirizzo di nulla; non solo una stringa. "

Quindi, ci si deve chiedere come si traduce il puntatore generale in Ada, in particolare in modo tale da sfruttare le funzioni di digitazione e sottotitolazione. Vorrei affermare che un "nulla", in questo contesto, non può essere risolto in generale; vale a dire, se vuoi mantenere la "flessibilità" del costrutto, devi sacrificare i vantaggi che Ada offre con il suo sistema di tipi. Inoltre, presento che presentato così com'è, è generalmente impossibile utilizzare in modo affidabile per "qualsiasi cosa".

Dico questo perché non esiste un metodo per determinare anche la lunghezza del contenuto "nulla". Se si tratta di una stringa, la lunghezza è dall'indirizzo puntato, conteggio consecutivo, fino al primo carattere NUL (ASCII 0) . Tuttavia, non esiste un metodo per determinare la lunghezza se non è una stringa (come potremmo conoscere la lunghezza/dimensione della matrice [1,2,3] o OBJECT) ... e quindi non abbiamo alcun metodo per determinare anche la lunghezza lunghezza del "nulla".

Determinare la lunghezza è un fattore importante nella scrittura di codice stabile/sicuro, perché se non si invitano buffer overflow.


Ma, lasciando che fuori, se è possibile fornire alcune informazioni sui dati, sia attraverso il parametro o cambiare my_struct, allora possiamo utilizzare queste informazioni per costruire una migliore tipo di conversione. (In generale, più informazioni hai su un tipo meglio è, perché puoi verificare la validità dei dati in modi che non avresti potuto prima, o meglio ancora, fare controllare il compilatore per te.)

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; 

È possibile utilizzare quanto sopra per generare una matrice di numeri interi senza segno a 8 bit che conterrebbe i dati dal flusso. Delinea quello che dovresti fare nel caso generale, anche se dal momento che stai lavorando con C-imports, ciò che puoi fare è modificarlo un po 'in modo che a) ci sia una variabile Temp che è una matrice come Result ma usa For Temp'Address Use [...] per sovrapporlo a my_type.value e quindi utilizzare il ciclo for per copiarlo.