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.)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
Tempvariable which is an array likeResultbut useFor Temp'Address Use [...]to overlay it on the my_type.value and then use the for-loop to copy it out.