Convert Ada string to C Void *

What is a good way to "distinguish" Ada String from System.Adress , which would be equivalent to casting char* to void* in C.

I interact with the C library. Type C has a property of type void* , and library users usually assign this value to the address pointed to by the C-string. For instance:

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

How can I achieve equivalent in Ada starting with Ada String?

I am using this technique at the moment, but it seems suspicious to me.

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

I am fine with any solution, even Ada 2012.

+6
source share
1 answer

You note in a comment that you are using void* "because it should be able to accept an address, not just a string.

So, you need to ask how the generic pointer translates to Ada, especially in such a way as to use the input and subtype functions. I would say that “nothing” in this context can be resolved as a whole; that is, if you want to maintain the "flexibility" of the design, you must sacrifice the benefits that Ada provides with its typical system. In addition, I affirm that presented as is, it is generally impossible to reliably use it for "nothing."

I say this because there is no method for determining even the length of the contained “nothing”. If it is a string, then the length is indicated with the pointing address, counting sequentially, up to the first NUL character (ASCII 0). However, there is no way to determine the length if it is not a string (how to know the length / size of an array [1,2,3] or OBJECT) ... and therefore we have no method for determining even the length of "nothing".

Determining the length is an important factor when writing stable / secure code, because if you do not, you cause a buffer overflow.


But, if this can be done, if you can provide some information about the data, whether through a parameter or by changing my_struct , then we can use this information to build a better type conversion. (In general, the more information you have about a type, the better, because you can verify the validity of the data in ways you could not before, or, even better, verify that this is a compiler for you.)

 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; 

You can use the above to create an array of 8-bit unsigned integers that will contain data from the stream. It describes what you need to do in the general case, although since you are working with C-import, you can change it a bit so that: a) there is a Temp variable, which is an array of type Result , but use For Temp'Address Use [...] to overlay it on my_type.value, and then use the for-loop to copy it.

+2
source

Source: https://habr.com/ru/post/908294/


All Articles