What is a good way to "cast" an Ada String
to a System.Adress
which would be equivalent to casting char*
to void*
in C.
I am interfacing which a C library. A C type has a property which is of type void*
, and users of the library typically assign the address pointed to by a C-string as this value. E.g:
struct my_type {
void* value;
};
int main() {
my_type t;
t.value = "banana";
}
How can I achieve the equivalent in Ada, starting with an Ada String?
I'm using this technique at the moment, but it seems fishy 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'm OK with any solution, even Ada 2012.
You mention in a comment that you're using void*
“because it should be able to take the address of anything; not just a string.”
So then, one has to ask how does the general-pointer translate into Ada, particularly in such a way as to take advantage of the typing and sub-typing features. I would submit that an “anything”, in this context, cannot be solved generally; that is to say, if you want to maintain the 'flexibility' of the construct you must sacrifice the advantages Ada provides with its type-system. Furthermore, I submit that presented as-is, it is generally impossible to reliably use for “anything”.
I say this because there is no method of determining even the length of the contained “anything.” If it's a string then the length is from the pointed-address, counting consecutively, until the first NUL character (ASCII 0). However, there is no method for determining the length if it is not a string (how would we know the length/size of array [1,2,3] or OBJECT)... and so we have no method for determining even the length of the “anything.”
Determining the length is an important factor in writing stable/secure code, because if you don't you're inviting buffer overflows.
But, leaving that off, if you can provide some information on the data, whether via parameter or changing my_struct
, then we can use that information to build a better type-conversion. (In general, the more information you have about a type the better, because you can then check for validity-of-data in ways you couldn't before; or better yet, have the compiler check that 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 generate an array of 8-bit unsigned integers which would contain the data from the the stream. It outlines what you'd have to do in the general case, though since you're working with C-imports what you can do is modify it a bit so that a) there is a Temp
variable which is an array like Result
but use For Temp'Address Use [...]
to overlay it on the my_type.value and then use the for-loop to copy it out.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With