Next: , Previous: Storage_Size Clauses, Up: Representation Clauses and Pragmas


9.4 Size of Variant Record Objects

In the case of variant record objects, there is a question whether Size gives information about a particular variant, or the maximum size required for any variant. Consider the following program

    with Text_IO; use Text_IO;
    procedure q is
       type R1 (A : Boolean := False) is record
         case A is
           when True  => X : Character;
           when False => null;
         end case;
       end record;
    
       V1 : R1 (False);
       V2 : R1;
    
    begin
       Put_Line (Integer'Image (V1'Size));
       Put_Line (Integer'Image (V2'Size));
    end q;

Here we are dealing with a variant record, where the True variant requires 16 bits, and the False variant requires 8 bits. In the above example, both V1 and V2 contain the False variant, which is only 8 bits long. However, the result of running the program is:

    8
    16

The reason for the difference here is that the discriminant value of V1 is fixed, and will always be False. It is not possible to assign a True variant value to V1, therefore 8 bits is sufficient. On the other hand, in the case of V2, the initial discriminant value is False (from the default), but it is possible to assign a True variant value to V2, therefore 16 bits must be allocated for V2 in the general case, even fewer bits may be needed at any particular point during the program execution.

As can be seen from the output of this program, the 'Size attribute applied to such an object in GNAT gives the actual allocated size of the variable, which is the largest size of any of the variants. The Ada Reference Manual is not completely clear on what choice should be made here, but the GNAT behavior seems most consistent with the language in the RM.

In some cases, it may be desirable to obtain the size of the current variant, rather than the size of the largest variant. This can be achieved in GNAT by making use of the fact that in the case of a subprogram parameter, GNAT does indeed return the size of the current variant (because a subprogram has no way of knowing how much space is actually allocated for the actual).

Consider the following modified version of the above program:

    with Text_IO; use Text_IO;
    procedure q is
       type R1 (A : Boolean := False) is record
         case A is
           when True  => X : Character;
           when False => null;
         end case;
       end record;
    
       V2 : R1;
    
       function Size (V : R1) return Integer is
       begin
          return V'Size;
       end Size;
    
    begin
       Put_Line (Integer'Image (V2'Size));
       Put_Line (Integer'Image (Size (V2)));
       V2 := (True, 'x');
       Put_Line (Integer'Image (V2'Size));
       Put_Line (Integer'Image (Size (V2)));
    end q;

The output from this program is

    16
    8
    16
    16

Here we see that while the 'Size attribute always returns the maximum size, regardless of the current variant value, the Size function does indeed return the size of the current variant value.