2012-02-13 9 views
6

¿Qué es una buena manera de "fundido" una Ada String a un System.Adress lo que sería equivalente a la fundición char* a void* en C.conversión de Ada cadena de C Void *

estoy de interfaz, que una biblioteca C. Un tipo C tiene una propiedad que es del tipo void*, y los usuarios de la biblioteca suelen asignar la dirección apuntada por una cadena C como este valor. E.g:

struct my_type { 
    void* value; 
}; 

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

¿Cómo puedo lograr el equivalente en Ada, comenzando con una cadena Ada?

Estoy usando esta técnica en este momento, pero me parece sospechosa.

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

estoy bien con cualquier solución, incluso Ada 2012.

+2

Debería echarle un vistazo al paquete 'Interfaces.C.Strings', que contiene un tipo' chars_ptr'. La función C que importa debe usar el tipo chars_ptr en lugar del vacío *. – oenone

+2

Además, mire las soluciones sugeridas aquí: http://en.wikibooks.org/wiki/Ada_Programming/Types/access#Where_is_void.2A.3F – oenone

+0

El miembro 'void *' del tipo es 'void *' porque debería poder tomar la dirección de cualquier cosa; no solo una cadena.Es por eso que 'g ++' generó la especificación de Ada para él y usó 'System.Address'. Encuentro que la técnica actualmente está funcionando. Tal vez es el sonido? – Anthony

Respuesta

2

Usted menciona en un comentario que está utilizando void* “, ya que debe ser capaz de tomar la dirección de la nada; no solo una cadena. "

Entonces, uno tiene que preguntarse cómo se traduce el puntero general a Ada, particularmente de forma que se aprovechen las características de mecanografía y subtipo. Yo diría que un "cualquier cosa", en este contexto, no puede resolverse en general; es decir, si desea mantener la "flexibilidad" de la construcción, debe sacrificar las ventajas que Ada proporciona con su sistema de tipos. Además, presento que presentado tal cual, generalmente es imposible de usar de manera confiable para "cualquier cosa".

Lo digo porque no hay un método para determinar incluso la longitud del "nada" contenido. Si es una cadena, la longitud es desde la dirección apuntada, contando consecutivamente, hasta el primer carácter NUL (ASCII 0) . Sin embargo, no hay un método para determinar la longitud si no es una cadena (¿cómo sabríamos la longitud/tamaño de la matriz [1,2,3] u OBJETO) ... y entonces no tenemos ningún método para determinar incluso el longitud del "cualquier cosa".

La determinación de la longitud es un factor importante al escribir código estable/seguro, porque si no está invitando desbordamientos de búfer.


Pero, dejando que fuera, si usted puede proporcionar alguna información sobre los datos, ya sea a través del parámetro o cambiar my_struct, entonces podemos usar esa información para construir un mejor tipo de conversión. (En general, mientras más información tenga sobre un tipo, mejor, porque luego puede verificar la validez de los datos de una manera que no podría hacerlo antes, o mejor aún, hacer que el compilador lo compruebe)

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; 

Puede utilizar lo anterior para generar una matriz de enteros sin signo de 8 bits que contendría los datos de la secuencia. Describe lo que tendrías que hacer en el caso general, aunque como estás trabajando con C-imports lo que puedes hacer es modificarlo un poco para que a) haya una variable Temp que es una matriz como Result pero usa For Temp'Address Use [...] para superponerlo en my_type.value y luego usar for-loop para copiarlo.