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=-1.9 required=5.0 tests=BAYES_00 autolearn=unavailable autolearn_force=no version=3.4.4 Path: eternal-september.org!reader01.eternal-september.org!feeder.eternal-september.org!news.swapon.de!fu-berlin.de!uni-berlin.de!individual.net!not-for-mail From: Niklas Holsti Newsgroups: comp.lang.ada Subject: Re: Problem with Position of the enumeration Type Date: Wed, 23 Jan 2019 23:42:49 +0200 Organization: Tidorum Ltd Message-ID: References: <3d782720-227d-4d86-b403-eacbd1b9d0d2@googlegroups.com> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit X-Trace: individual.net WElg4owAvKPym52h6CYtLAQzr4SOhjN21XfOmCQcv3dZeSedVb Cancel-Lock: sha1:sHzf8i5e7XY15RcASutni71kw38= User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:45.0) Gecko/20100101 Thunderbird/45.8.0 In-Reply-To: <3d782720-227d-4d86-b403-eacbd1b9d0d2@googlegroups.com> Xref: reader01.eternal-september.org comp.lang.ada:55344 Date: 2019-01-23T23:42:49+02:00 List-Id: On 19-01-23 12:05 , Luis Ladron de Guevara Moreno wrote: > Hello, > > I have an issue with the declaration of the enumeration type, > when i try to map the values of an enumeration to a specific position. > > the code: > > procedure EnumerationTest is > > Position : Integer; > > type E_Test is (Pos10, Pos11, Pos12, Pos13, Pos14); > > for E_Test use (Pos10 => 10, > Pos11 => 11, > Pos12 => 12, > Pos13 => 13, > Pos14 => 14); > > begin > > for I in E_Test'Base loop > > Position := E_Test'pos (I); > ada.Text_IO.Put (" Position: " & Position'Img & " Value: " & I'Img); > end loop; > > end EnumerationTest; > > i thought that the result of the position was 10, > 11, 12, 13, 14. But When i run this code, the result > is 0, 1, 2, 3. I don't know what it is the exactly meaning of: > > for E_Test use (Pos10 => 10, > Pos11 => 11, > Pos12 => 12, > Pos13 => 13, > Pos14 => 14); > > and how can i assign a different position for the specific value. The point is that Ada enumeration literals are not merely synonyms for integer values, unlike C enums. The list of names (enumeration literals) in the declaration of the enumerated type defines the position numbers, which always start from 0 and increase by 1 for each literal. These position numbers, which can be queried with the 'Pos attribute, are independent of the possible "for .. use" representation clause for the enumeration. On the next level -- physical representation -- if you have code like E : E_Test; ... E := Pos12; you can ask as follows: The compiler allocates a memory location for the object E. Let's say that an octet of 8 bits is allocated. What are the values of these 8 bits after the assignment of Pos12 to E? In other words, which bit pattern in memory represents the logical value Pos12? This question is answered by the presence (or absence) of a "for E_Test use" representation clause: - if there is no such clause, the value of the bits is given by the position number, which for Pos12 is 2 (2#0000_0010# in binary) - if there is such a clause, the value of the bits is given by the representation value in that clause, which for Pos12 is 12 (binary 2#0000_1100#) using the values in your example. As others have remarked, you can discover the representation value by an Unchecked_Conversion from E_Test to some integer type (with the same number of bits), or by the GNAT-specific attribute 'Enum_Rep. In your example, the representation values are contiguous, but there can also be gaps, for example: for E_Test use (Pos10 => 10, Pos11 => 21, Pos12 => 34, Pos13 => 100, Pos14 => 255); (However, the representation values must be in ascending order, so that their order is the same as the position-number order.) The important points to note are that the 'Pos values still run from 0 to 4, and most importantly that the 'Succ and 'Pred attribute functions "skip" the gaps, so that, for example, E := E_Test'Succ (Pos11); makes E = Pos12, represented in memory as 34. Thus, 'Succ is not just "add one to the value", but "take the next representation value". As an aside, this means that 'Succ and 'Pred on enumeration types with "gappy" representations can be much more expensive (in processor time) than for enumeration types with gap-less representations or default representations. For this reason, Ada design and coding rules for embedded/critical systems often place restrictions on enumeration types with representation clauses, for example that 'Succ, 'Pred and the like should not be used for such types. Such rules also commonly say that such types should not be used as array index types, because of the possible introduction of gaps in the array representations. Furthermore, if you loop over an enumeration with a gappy representations, such as for E in E_Test loop ... end loop; the loop will use _only_ the valid representations. So the bits holding the value of the loop-counter E will successively take on the values 10, 21, 34, 100, 255, but will skip the values in between. This is quite different from what would happen in C. As others have also noted, enumeration representation clauses are used mostly when the enumeration value is an input (say, from some memory-mapped control register, or from a binary input file) or an output. Communication protocols and HW interfaces often define fields that encode some finite set of possible logical values/meanings, but where the encoding has gaps. A final note: if you use an enumerated type for an input value, it is wise to check if the input is valid before using it. Use the 'Valid attribute for this. However, this attribute can also have a non-trivial cost. For example, the compiler may implement the function call E_Test'Valid(E) by code that compares the (representation of) E against each of the valid values 10, 21, 34, 100, 255 in turn (although a better compiler would use a binary search). An alternative I often use is to define the enumerated type with default representation (= position numbers), define the input as an integer (in this case 0 .. 255), and translate from input to enumeration with an array, like this: type Input_Value is range 0 .. 255; E_For_Input : constant array (Input_Value) of E_Test is := ( 10 => Pos10, 21 => Pos11, 34 => Pos12, 100 => Pos13, 255 => Pos14, others => Pos_Invalid); where I assume that E_Test is extended with the literal Pos_Invalid. Given an input value In, the corresponding enumeration value E is obtained by E := E_For_Input(I), and validity can be checked by "if E /= Pos_Invalid then ..." instead of using E_Test'Valid. A similar translation can be used to map an internal enumeration (with default representation) to an external, gappy, output encoding. These alternatives (array-based translations) have the advantage, compared to enumeration representation clauses, that the representation values (external input/output values) can use a different order than the enumerated type. This can make it easier to define logical subtypes (sub-ranges) of the enumerated type. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ .