From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=0.7 required=5.0 tests=BAYES_00,MSGID_RANDY autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,76be2011d1dba323 X-Google-Attributes: gid103376,public From: Robert Dewar Subject: Re: Convert an address range into an array Date: 1999/06/06 Message-ID: <7jdrl4$ttq$1@nnrp1.deja.com> X-Deja-AN: 486285074 References: <7jdjov$21$1@pegasus.csx.cam.ac.uk> X-Http-Proxy: 1.0 x33.deja.com:80 (Squid/1.1.22) for client 205.232.38.14 Organization: Deja.com - Share what you know. Learn what you don't. X-Article-Creation-Date: Sun Jun 06 13:04:38 1999 GMT Newsgroups: comp.lang.ada X-Http-User-Agent: Mozilla/4.04 [en] (OS/2; I) Date: 1999-06-06T00:00:00+00:00 List-Id: In article <7jdjov$21$1@pegasus.csx.cam.ac.uk>, mgk25@cl.cam.ac.uk (Markus Kuhn) wrote: >Basically, I want to get somehow a value > S : String; >such that > S(S'First)'Access = A > S(S'Last)'Access = B > S'First = 1 >(where A and B are two addressses) Well we are not going to be able to find a solution that is *formally* portable for something like this, but we can certainly find a solution that is from a pragmatic point of view portable (between architectures and between compilers). There are a couple of approaches. First, let's try to get a type that retains proper bounds checking: First, we want to deal with a constrained array here. Unconstrained arrays have bounds stored in some implementation dependent format and will get you into trouble. So let's first define a subtype that appropriately represents the range subtype XString is String (1 .. expr); Here expr can be dynamic, there is no problem in that. However, note that we must define this subtype in an appropriate scope. In this particular case, expr is something like Positive (System.Storage_Elements.To_Integer (B) - System.Storage_Elements.To_Integer (A) + 1); Now we can proceed in several ways Method 1a. Simply use an address clause. This is exactly a legitimate use of address clauses, so we simply say S : XString; for S'Address use A; This will likely work on most implementations, assuming that they do not use dope vectors or descriptors for constrained arrays. This is a reasonable assumption, and certainly true of GNAT, but in practice it may be slightly more portable to use: Method 1b. Use Unchecked_Conversion type XString_Ptr is access all XString; function To_XString_Ptr is new Unchecked_Conversion (Address, XString_Ptr); SP : XString_Ptr := To_String_Ptr (A); in practice, this works fine, since all implementations will use the same representation for constrained pointers and addresses. Note that approach 1b will NOT work if you try to use "access string" instead of the pointer-to-constrained type, since then bounds get involved. However, there is no requirement that this work, so a bit cleaner, is to use: Method 1c. Use Address_To_Access_Conversions package XString_Ops is new Address_To_Access_Conversions (XString); subtype Xstring_Ptr is Xstring_Ops.Object_Pointer; SP : XString_Ptr := To_Pointer (A); Note: although the formal of this package has a declaration (<>) implying you can use it with an unconstrained type such as String, you will get into trouble if you try, since we still have the bounds problem. Basically the issue with "access String" is that values of this type have bounds. Where are these bounds stored? Certainly your memory mapped gizmo has no bounds in sight, and even if it did your implementation might not have the same idea of how to store them. Here are two rules to follow NEVER use unchecked conversion with pointers to unconstrained array types NEVER use Address_To_Access_Conversions with pointers to unconstrained array types. Violating these rules is a common cause of non-portable code and obscure bugs. We find this coming up frequently in our work helping customers to port legacy Ada 83 code. OK, those approaches work fine, but now for one other approach that is a little more general and flexible, but does not retain bounds checking. Define a type subtype Big_String is String (Positive); type Big_String_Ptr is access Big_String; This type acts very much like char* in C in that it is a pointer that can be used to access arbitrary sized character arrays. Method 2b. Like 1b but use Big_String_Ptr Method 2c. Like 1c but use Big_String_Ptr The advantage of Method 2b and 2c is that Big_String_Ptr can be used arround the place freely without worrying about specialized definitions of subtypes and their scopes. This approach is also appropriate when you don't know the upper bound in advance, but it is computed as you go along, or changes as you go along. For an example of the use of "Big" arrays of this type, see the GNAT.Table package in the GNAT library, which uses this approach to get the effect of virtual origin addressing for arrays. Method 3. Pointer Arithmetic Finally, yes, you could use address arithmetic (good old pointer arithmetic), and indeed Ada has much more flexible pointer arithmetic than C (in Ada, unlike C, you can do arbitrary address arithmetic, e.g. compare any two addresses, in a portable manner). However, this is much lower level and will kludge up your code unnecessarily. Ada 83 notes. In Ada 83, method 1a is a bit more dubious, it may be erroneous, but in practice if the addressed area is not otherwise aliased, it should work fine. Method 1b is certainly safe (same comments apply to 2a and 2b). Method 1c, probably the preferable approach for Ada 95 is of course not available in Ada 83. Robert Dewar Ada Core Technologies P.S. It is quite true that this sort of thing is not very well documented in the Ada literature. We find that issues like this now account for a substantial part of the support work we provide for our customers. Choosing the right way to solve problems like this is critical, and you often find a lot of bad advice on how to proceed, contaminated with a lack of clear knowledge on what is and what is not likely to be implementation dependent. This is the sort of place where programmers need to be aware of what they are doing at a low level as well as a high level. As I noted in previous posts, this is often missing knowledge. Thanks, Marcus for an instructive question :-) Sent via Deja.com http://www.deja.com/ Share what you know. Learn what you don't.