Difference between revisions of "Studio:Scl union"

From STRIDE Wiki
Jump to: navigation, search
(Examples)
Line 79: Line 79:
  
 
The following examples illustrate how various discriminant values map to the active member for discriminated unions:
 
The following examples illustrate how various discriminant values map to the active member for discriminated unions:
 
:# [[Scl_union#Example_1:_Default_mapping|Default mapping]]: Discriminant is an integral type. A value of n maps to the nth union member. Members are numbered beginning with zero (0).
 
:# [[Scl_union#Example_2:_Enum-based|Enum-based]]: Discriminant is an enumerated type. The nth enumeration constant (in declared order, not value order) maps to the nth union member.
 
:# [[Scl_union#Example_3:_Explicit_mapping|Explicit mapping]]: Discriminant values are explicitly mapped to active union members using scl_union_activate().
 
:# [[Scl_union#Example_4:_Discriminant_values_constrained_to_enumeration_types|Discriminant values constrained to enumeration type]]: an integer-based discriminant is constrained (using scl_values) to an enumerated type. This sets up an enum-based mapping as described in Example 2.
 
:# [[Scl_union#Example_5:_Default_undiscriminated_union|Default undiscriminated union]]: the union does not have a discriminant. The first member is always assumed to be active.
 
:# [[Scl_union#Example_6:_Explicitly_prescribed_fixed_active_member_for_undiscriminated_union|Explicitly prescribed fixed active member for undiscriminated union]]: the union does not have a discriminant. scl_union is used to prescribe a specific member as always active.
 
:# [[Scl_union#Example_7:_Internal_discriminant|Internal discriminant]]: an internal discriminant is located inside the union.
 
:# [[Scl_union#Example_8:_Explicit_mapping_of_multiple_discriminant_values_to_a_single_active_member|Explicit mapping of multiple discriminant values to a single active member]].
 
:# [[Scl_union#Example_9:_Unmapped_discriminant_values_indicating_no_member_is_active|Unmapped discriminant values indicating no member is active]].
 
:# [[Scl_union#Example_10:_Discriminant_values_defined_by_macros|Discriminant values defined by macros]].
 
  
 
=== Example 1: Default mapping ===
 
=== Example 1: Default mapping ===
 
+
Discriminant is an integral type. A value of n maps to the nth union member. Members are numbered beginning with zero (0).
    typedef struct {
+
<source lang=c>
        int disc;
+
typedef struct {
        union {
+
  int disc;
            int i;
+
  union {
            float f;
+
    int i;
        } u;
+
    float f;
    } S1t;
+
  } u;
 +
} S1t;
 
   
 
   
    #pragma scl_union(S1t.u, S1t.disc)
+
#pragma scl_union(S1t.u, S1t.disc)
 +
</source>
  
 
=== Example 2: Enum-based ===
 
=== Example 2: Enum-based ===
    typedef enum {
+
Discriminant is an enumerated type. The nth enumeration constant (in declared order, not value order) maps to the nth union member.
        IDX_FIRST  = 20,
+
<source lang=c>
        IDX_SECOND = 4
+
typedef enum {
    } e_t;
+
  IDX_FIRST  = 20,
 +
  IDX_SECOND = 4
 +
} e_t;
 
   
 
   
    typedef struct {
+
typedef struct {
        e_t disc;
+
  e_t disc;
        union {
+
  union {
            int i;
+
    int i;
            float f;
+
    float f;
        } u;
+
  } u;
    } S2t;
+
} S2t;
 
   
 
   
    #pragma scl_union(S2t.u, S2t.disc)
+
#pragma scl_union(S2t.u, S2t.disc)
 +
</source>
  
 
=== Example 3: Explicit mapping ===
 
=== Example 3: Explicit mapping ===
    // In the following union:
+
Discriminant values are explicitly mapped to active union members using scl_union_activate().
    //    discriminant == 4 means 'i' is active
+
<source lang=c>
    //    discriminant == 5 means 'f' is active
+
// In the following union:
    typedef struct {
+
//    discriminant == 4 means 'i' is active
        int discriminant;
+
//    discriminant == 5 means 'f' is active
        union {
+
typedef struct {
            int i;
+
  int discriminant;
            float f;
+
  union {
        } u;
+
    int i;
    } S;
+
    float f;
 +
  } u;
 +
} S;
 
   
 
   
    #pragma scl_union (S.u, S.discriminant)
+
#pragma scl_union (S.u, S.discriminant)
    #pragma scl_union_activate (S.u, i, 4)
+
#pragma scl_union_activate (S.u, i, 4)
    #pragma scl_union_activate(S.u, f, 5)
+
#pragma scl_union_activate(S.u, f, 5)
 +
</source>
  
 
=== Example 4: Discriminant values constrained to enumeration types ===
 
=== Example 4: Discriminant values constrained to enumeration types ===
    // In the following union:
+
An integer-based discriminant is constrained (using scl_values) to an enumerated type. This sets up an enum-based mapping as described in Example 2.
    //    discriminant == RED means 'i' is active
+
<source lang=c>
    //    discriminant == GREEN means 'f' is active
+
// In the following union:
    //    discriminant == BLUE means 'd' is active
+
//    discriminant == RED means 'i' is active
    typedef enum {
+
//    discriminant == GREEN means 'f' is active
        RED,
+
//    discriminant == BLUE means 'd' is active
        GREEN,
+
typedef enum {
        BLUE
+
  RED,
    } COLOR;
+
  GREEN,
 +
  BLUE
 +
} COLOR;
 
   
 
   
    typedef struct {
+
typedef struct {
        int discriminant;
+
  int discriminant;
        union {
+
  union {
            int i;
+
    int i;
            float f;
+
    float f;
            double d;
+
    double d;
        } u;
+
  } u;
    } S;
+
} S;
 
   
 
   
    #pragma scl_union (S.u, S.discriminant)
+
#pragma scl_union (S.u, S.discriminant)
    #pragma scl_values (S.discriminant, COLOR)
+
#pragma scl_values (S.discriminant, COLOR)
 +
</source>
 
   
 
   
 
=== Example 5: Default undiscriminated union ===
 
=== Example 5: Default undiscriminated union ===
    //In the following union:
+
The union does not have a discriminant. The first member is always assumed to be active.
    //  'i' is always treated as active
+
<source lang=c>
    typedef struct {
+
//In the following union:
        union {
+
//  'i' is always treated as active
            int i;
+
typedef struct {
            float f;
+
  union {
        } u;
+
    int i;
    } S6t;
+
    float f;
 +
  } u;
 +
} S6t;
 +
</source>
  
 
=== Example 6: Explicitly prescribed fixed active member for undiscriminated union ===
 
=== Example 6: Explicitly prescribed fixed active member for undiscriminated union ===
 
+
The union does not have a discriminant. scl_union is used to prescribe a specific member as always active.
    typedef struct {
+
<source lang=c>
        union {
+
typedef struct {
            int i;
+
  union {
            float f;
+
    int i;
            char bytes[4];
+
    float f;
        } u;
+
    char bytes[4];
    } S6t;
+
  } u;
 +
} S6t;
 
   
 
   
    /* Select field "bytes" as the default member */
+
/* Select field "bytes" as the default member */
    #pragma scl_union(S6t.u, 2)
+
#pragma scl_union(S6t.u, 2)
 +
</source>
  
 
=== Example 7: Internal discriminant ===
 
=== Example 7: Internal discriminant ===
    // Union with internal discriminant:
+
An internal discriminant is located inside the union.
    //    discriminant == 0    'um0' is active member
+
<source lang=c>
    //    discriminant == 1    'um1' is active member
+
// Union with internal discriminant:
    //    discriminant == 2    'um2' is active member
+
//    discriminant == 0    'um0' is active member
    typedef struct {
+
//    discriminant == 1    'um1' is active member
        int discriminant;
+
//    discriminant == 2    'um2' is active member
    } HEADER;
+
typedef struct {
 +
  int discriminant;
 +
} HEADER;
 
   
 
   
    typedef struct {
+
typedef struct {
        HEADER h;
+
  HEADER h;
        int x;
+
  int x;
    } UNION_MEMBER_0;
+
} UNION_MEMBER_0;
 
   
 
   
    typedef struct {
+
typedef struct {
        HEADER h;
+
  HEADER h;
        float f;
+
  float f;
    } UNION_MEMBER_1;
+
} UNION_MEMBER_1;
 
   
 
   
    typedef struct {
+
typedef struct {
        HEADER h;
+
  HEADER h;
        double d;
+
  double d;
    } UNION_MEMBER_2;
+
} UNION_MEMBER_2;
 
   
 
   
    typedef union {
+
typedef union {
        UNION_MEMBER_0  um0;
+
  UNION_MEMBER_0  um0;
        UNION_MEMBER_1  um1;
+
  UNION_MEMBER_1  um1;
        UNION_MEMBER_2  um2;
+
  UNION_MEMBER_2  um2;
    } U;
+
} U;
 
   
 
   
    #pragma scl_union(U, U.um0.h.discriminant)
+
#pragma scl_union(U, U.um0.h.discriminant)
 +
</source>
  
 
=== Example 8: Explicit mapping of multiple discriminant values to a single active member ===
 
=== Example 8: Explicit mapping of multiple discriminant values to a single active member ===
 
+
<source lang=c>
    typedef struct {
+
typedef struct {
        int a;
+
  int a;
        int b;
+
  int b;
    } type1_t;
+
} type1_t;
 
      
 
      
    typedef struct {
+
typedef struct {
        float x;
+
  float x;
        float y;
+
  float y;
    } type2_t;
+
} type2_t;
 
      
 
      
    typedef struct {
+
typedef struct {
        char c1;
+
  char c1;
        char c2;
+
  char c2;
    } type3_t;
+
} type3_t;
 
      
 
      
    typedef enum {
+
typedef enum {
        ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE
+
  ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE
    } discriminant_t;
+
} discriminant_t;
 
      
 
      
    typedef struct {
+
typedef struct {
        discriminant_t d;
+
  discriminant_t d;
        int e;
+
  int e;
        union {
+
  union {
            type1_t m1;    // active when d == ONE or d == TWO or d == THREE
+
    type1_t m1;    // active when d == ONE or d == TWO or d == THREE
            type2_t m2;    // active when d == FOUR or d == SIX or d == EIGHT
+
    type2_t m2;    // active when d == FOUR or d == SIX or d == EIGHT
            type3_t m3;    // active when d == FIVE or d == SEVEN
+
    type3_t m3;    // active when d == FIVE or d == SEVEN
        } u_main;
+
  } u_main;
    } s_t;
+
} s_t;
+
 
    #pragma scl_union (s_t.u_main, s_t.d)
+
#pragma scl_union (s_t.u_main, s_t.d)
    #pragma scl_union_activate(s_t.u_main, m1, ONE, TWO, THREE)
+
#pragma scl_union_activate(s_t.u_main, m1, ONE, TWO, THREE)
    #pragma scl_union_activate(s_t.u_main, m2, FOUR, SIX, EIGHT)
+
#pragma scl_union_activate(s_t.u_main, m2, FOUR, SIX, EIGHT)
    #pragma scl_union_activate(s_t.u_main, m3, FIVE, SEVEN)
+
#pragma scl_union_activate(s_t.u_main, m3, FIVE, SEVEN)
 +
</source>
  
 
=== Example 9: Unmapped discriminant values indicating no member is active ===
 
=== Example 9: Unmapped discriminant values indicating no member is active ===
 +
<source lang=c>
 +
//Union unmapped discriminant values
 +
//
 +
//    discriminant == ZERO                  'i' is active member
 +
//    discriminant == ONE                  'f' is active member
 +
//    discriminant == TWO                  'd' is active member
 +
//    discriminant == THREE or FOUR
 +
//                    FIVE or SIX or SEVEN      no active member
 +
typedef enum {
 +
  ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN
 +
} ENUM_TYPE;
 +
   
 +
typedef struct {
 +
  ENUM_TYPE discriminant;
 +
  union {
 +
    int    i;
 +
    float  f;
 +
    double d;
 +
  } u;
 +
} S;
  
    //Union unmapped discriminant values
+
#pragma scl_union (S.u, S.discriminant)
    //
+
#pragma scl_union_activate(S.u, i, ZERO)
    //    discriminant == ZERO                  'i' is active member
+
#pragma scl_union_activate(S.u, f, ONE)
    //    discriminant == ONE                  'f' is active member
+
#pragma scl_union_activate(S.u, d, TWO)
    //    discriminant == TWO                  'd' is active member
+
</source>
    //    discriminant == THREE or FOUR
 
    //                    FIVE or SIX or SEVEN      no active member
 
    typedef enum {
 
        ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN
 
    } ENUM_TYPE;
 
   
 
    typedef struct {
 
        ENUM_TYPE discriminant;
 
        union {
 
            int    i;
 
            float  f;
 
            double d;
 
        } u;
 
    } S;
 
   
 
    #pragma scl_union (S.u, S.discriminant)
 
    #pragma scl_union_activate(S.u, i, ZERO)
 
    #pragma scl_union_activate(S.u, f, ONE)
 
    #pragma scl_union_activate(S.u, d, TWO)
 
  
 
=== Example 10: Discriminant values defined by macros ===
 
=== Example 10: Discriminant values defined by macros ===
 
+
<source lang=c>
    //One field discriminating multiple unions  
+
//One field discriminating multiple unions  
    //
+
//
    //    discriminant == 1                  'i' is active member
+
//    discriminant == 1                  'i' is active member
    //    discriminant == 2                  'f' is active member
+
//    discriminant == 2                  'f' is active member
    //    discriminant == 3                  'd' is active member
+
//    discriminant == 3                  'd' is active member
    //   
+
//   
    #define ONE  1
+
#define ONE  1
    #define TWO  2
+
#define TWO  2
    #define THREE 3
+
#define THREE 3
 
      
 
      
    typedef struct {
+
typedef struct {
        int discriminant;
+
  int discriminant;
        union {
+
  union {
            int    i;
+
    int    i;
            float  f;
+
    float  f;
            double d;
+
    double d;
        } u;
+
  } u;
    } S;
+
} S;
 
      
 
      
    #pragma scl_union (S.u, S.discriminant)        // uses 2-parameter form of scl_union
+
#pragma scl_union (S.u, S.discriminant)        // uses 2-parameter form of scl_union
    #pragma scl_union_activate (S.u, i, ONE)      // the first parameter identifies the union, the second a member in it.  
+
#pragma scl_union_activate (S.u, i, ONE)      // the first parameter identifies the union, the second a member in it.  
    #pragma scl_union_activate (S.u, f, TWO)
+
#pragma scl_union_activate (S.u, f, TWO)
    #pragma scl_union_activate (S.u, d, THREE)
+
#pragma scl_union_activate (S.u, d, THREE)
 +
</source>
  
 
== See Also ==
 
== See Also ==

Revision as of 18:46, 1 October 2008

The scl_union pragma

Unions are C language constructs that have a set of members, of which at most one can be stored in the union object at any time. The stored member is called the "active" member. The scl_union pragma identifies which union member is the active member when a union is part of a payload.

Syntax

#pragma scl_union(union-name, active-index)

#pragma scl_union(union-name, discriminant-specification)

#pragma scl_union(parent-name, union-name, active-index)

#pragma scl_union(parent-name, union-name, discriminant-specification)
Parameters Type Description
parent-name String Name of structure encapsulating the union
union-name String Name of the union
active-index Integer Zero-based index for the active overlay
discriminant-specification String Field name indicating the active overlay

Notes

For each union that is part of a message or function, there must be a means to determine which member is active. There are two basic methods for identification of the active member:

  • One union member is designated as always active. The union will be treated as if this member is permanently active, there is no discriminant, nor any way to change the active member.
  • A secondary field is designated as the discriminant and its value determines which (if any) of the union members are active.

Discriminants

Unions within the source code are easily identified by the "union" keyword. As discriminants are not easy to identify, the scl_union() pragma is necessary to identify them. The scl_union_activate() pragma is optionally used to define a mapping between discriminant values and union members.

Within a discriminated union, the discriminant value determines the active member of the union, resulting in a mapping between discriminant values and union members. A number of mapping choices are supported:

  • In the simplest mapping, a discriminant value of n directly identifies the nth union member as active. In other words, a value of 0 would indicate the first union member, a value of 1 would indicate the second, etc.
  • If the discriminant is an enumerated type, it is possible to set up an association between enumeration constants and active members such that the nth enumeration constant (in declared order, not value order) maps to the nth union member.
  • It is also possible to create an explicit map between discriminant value sets and active members by specifying that a particular value or set of values maps to a specific member.

The following constraints are enforced for the mapping between discriminant values and union members:

  • A particular discriminant value may map only to a single union member.
  • A particular field may act as a discriminant for more than one union
  • A single union may only have a single discriminant field.
  • The type of the discriminant field must be an integer or enumerated type or must have been cast (using scl_cast()) to an integer or enumerated type.
  • Any scl_values() pragma applied to the discriminant field affects the default mapping between discriminant values and union members.

Default Mapping

As mentioned previously, the scl_union() pragma is used to identify the discriminant for a union and scl_union_activate() is used to map discriminant values to union members. If there are no scl_union_activate() pragmas for a particular discriminated union, then the mapping between the discriminant and members is said to be default. The default mapping depends on the type of the discriminant:

  • If the discriminant is one of the standard integer types, or has been cast to one of the standard integer types using scl_cast(), then the value of the discriminant identifies the position of the active member; i.e., a value of 0 indicates the first union member, a value of 1 the second, etc.
  • If the discriminant is an enumerated type or has been cast to an enumerated type, or has had a set of constant values prescribed using scl_values(), then each constant has both a value and a position within the list. It is the position, rather than the value, that identifies the active member. When the discriminant takes on the value of the constant from position n, the nth union member is active. In the case of two constants from the same list have the same value, but different positions, an error is recognized.

Explicit Mappings

A union that has at least one scl_union_activate() pragma applied to it is said to have an explicit mapping. When a union has an explicit mapping, there is no default mapping; rather all mapping between discriminant values and union members is prescribed by the set of scl_union_activate() pragmas for the unions. For more details on using scl_union_activate(), click here.

Internal and External Discriminants

A union’s discriminant is either internal or external. A union has an external discriminant if the discriminant field is not contained within the union.

An internal discriminant is one that is located inside the union. If a union has an internal discriminant the following must be true:

  • Every member of the union must have a field that corresponds to the internal discriminant. All such fields must be of exactly the same type, or they must have had exactly the same scl_cast() or scl_values() specifications applied. Furthermore, all such fields must be positioned in exactly the same memory location within the union. If they are located in a payload block other than the one containing the union, then the expression "path" leading to each must be the same in the sense that all corresponding pointers across all the members have exactly the same offsets.

For additional information on scl_union, including constraints, refer to the section on scl_union in the [SCL Reference Guide].

Examples

The following examples illustrate how various discriminant values map to the active member for discriminated unions:

Example 1: Default mapping

Discriminant is an integral type. A value of n maps to the nth union member. Members are numbered beginning with zero (0).

typedef struct {
  int disc;
  union {
    int i;
    float f;
  } u;
} S1t;
 
#pragma scl_union(S1t.u, S1t.disc)

Example 2: Enum-based

Discriminant is an enumerated type. The nth enumeration constant (in declared order, not value order) maps to the nth union member.

typedef enum {
  IDX_FIRST  = 20,
  IDX_SECOND = 4
} e_t;
 
typedef struct {
  e_t disc;
  union {
    int i;
    float f;
  } u;
} S2t;
 
#pragma scl_union(S2t.u, S2t.disc)

Example 3: Explicit mapping

Discriminant values are explicitly mapped to active union members using scl_union_activate().

// In the following union:
//     discriminant == 4 means 'i' is active
//     discriminant == 5 means 'f' is active
typedef struct {
  int discriminant;
  union {
    int i;
    float f;
  } u;
} S;
 
#pragma scl_union (S.u, S.discriminant)
#pragma scl_union_activate (S.u, i, 4)
#pragma scl_union_activate(S.u, f, 5)

Example 4: Discriminant values constrained to enumeration types

An integer-based discriminant is constrained (using scl_values) to an enumerated type. This sets up an enum-based mapping as described in Example 2.

// In the following union:
//     discriminant == RED means 'i' is active
//     discriminant == GREEN means 'f' is active
//     discriminant == BLUE means 'd' is active
typedef enum {
  RED,
  GREEN,
  BLUE
} COLOR;
 
typedef struct {
  int discriminant;
  union {
    int i;
    float f;
    double d;
  } u;
} S;
 
#pragma scl_union (S.u, S.discriminant)
#pragma scl_values (S.discriminant, COLOR)

Example 5: Default undiscriminated union

The union does not have a discriminant. The first member is always assumed to be active.

//In the following union:
//   'i' is always treated as active
typedef struct {
  union {
    int i;
    float f;
  } u;
} S6t;

Example 6: Explicitly prescribed fixed active member for undiscriminated union

The union does not have a discriminant. scl_union is used to prescribe a specific member as always active.

typedef struct {
  union {
    int i;
    float f;
    char bytes[4];
  } u;
} S6t;
 
/* Select field "bytes" as the default member */
#pragma scl_union(S6t.u, 2)

Example 7: Internal discriminant

An internal discriminant is located inside the union.

// Union with internal discriminant:
//     discriminant == 0     'um0' is active member
//     discriminant == 1     'um1' is active member
//     discriminant == 2     'um2' is active member
typedef struct {
  int discriminant;
} HEADER;
 
typedef struct {
  HEADER h;
  int x;
} UNION_MEMBER_0;
 
typedef struct {
  HEADER h;
  float f;
} UNION_MEMBER_1;
 
typedef struct {
  HEADER h;
  double d;
} UNION_MEMBER_2;
 
typedef union {
  UNION_MEMBER_0   um0;
  UNION_MEMBER_1   um1;
  UNION_MEMBER_2   um2;
} U;
 
#pragma scl_union(U, U.um0.h.discriminant)

Example 8: Explicit mapping of multiple discriminant values to a single active member

typedef struct {
  int a;
  int b;
} type1_t;
    
typedef struct {
  float x;
  float y;
} type2_t;
    
typedef struct {
  char c1;
  char c2;
} type3_t;
    
typedef enum {
  ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE
} discriminant_t;
    
typedef struct {
  discriminant_t d;
  int e;
  union {
    type1_t m1;    // active when d == ONE or d == TWO or d == THREE
    type2_t m2;    // active when d == FOUR or d == SIX or d == EIGHT
    type3_t m3;    // active when d == FIVE or d == SEVEN
  } u_main;
} s_t;

#pragma scl_union (s_t.u_main, s_t.d)
#pragma scl_union_activate(s_t.u_main, m1, ONE, TWO, THREE)
#pragma scl_union_activate(s_t.u_main, m2, FOUR, SIX, EIGHT)
#pragma scl_union_activate(s_t.u_main, m3, FIVE, SEVEN)

Example 9: Unmapped discriminant values indicating no member is active

//Union unmapped discriminant values
//
//     discriminant == ZERO                  'i' is active member
//     discriminant == ONE                   'f' is active member
//     discriminant == TWO                   'd' is active member
//     discriminant == THREE or FOUR
//                     FIVE or SIX or SEVEN      no active member
typedef enum {
  ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN
} ENUM_TYPE;
    
typedef struct {
  ENUM_TYPE discriminant;
  union {
    int    i;
    float  f;
    double d;
  } u;
} S;

#pragma scl_union (S.u, S.discriminant)
#pragma scl_union_activate(S.u, i, ZERO)
#pragma scl_union_activate(S.u, f, ONE)
#pragma scl_union_activate(S.u, d, TWO)

Example 10: Discriminant values defined by macros

//One field discriminating multiple unions 
//
//     discriminant == 1                   'i' is active member
//     discriminant == 2                   'f' is active member
//     discriminant == 3                   'd' is active member
//  
#define ONE   1
#define TWO   2
#define THREE 3
    
typedef struct {
  int discriminant;
  union {
    int    i;
    float  f;
    double d;
  } u;
} S;
    
#pragma scl_union (S.u, S.discriminant)        // uses 2-parameter form of scl_union
#pragma scl_union_activate (S.u, i, ONE)       // the first parameter identifies the union, the second a member in it. 
#pragma scl_union_activate (S.u, f, TWO)
#pragma scl_union_activate (S.u, d, THREE)

See Also

  • For additional information on the scl_union pragma, including constraints, refer to the section on scl_union in the [SCL Reference Guide].