PreviousNext

Structures and Unions

There are no important policy issues relating to structures and unions as RPC parameters. Pointers and arrays as members of structures and unions are sometimes treated differently from separately declared types. By embedding pointers and arrays in structures and unions, you can sometimes achieve behavior that cannot be obtained by passing them as separate parameters.

Structures and unions can be used wherever they would be used in a non-RPC application. IDL structures differ from C language structures in one important respect: they may contain conformant arrays, which are not supported by C. A structure that contains a conformant array is itself conformant; that is, the size of the structure may not be determined until runtime. Applications need to do some extra work to determine the size of, and allocate, conformant structures. When structures are used to create linked lists and trees, the stubs do considerable work to insure that server allocated data is reflected back to the client.

IDL union syntax is quite different from C syntax, since IDL unions must be discriminated so that stubs can determine which of the contained data types to marshal. As with conformant and varying arrays, which use a field attribute variable to determine array size and bounds at runtime, IDL unions use a discriminator variable to determine which data type is marshalled.

IDL unions may be encapsulated or nonencapsulated. In an encapsulated union, the IDL compiler packages the union type and the discriminator in a structure. In a nonencapsulated union, the IDL switch_is] attribute is used to identify a discriminator variable. In this case, as in the case of array field attribute variables, the application must declare the discriminator and the union together, either as members of a structure or as parameters of an operation.

When a union is passed as a parameter, the value of the discriminator must either match one of the constants declared in the switch construct, or the switch must contain a default case. Otherwise, a stub marshalling error will occur.

Following are several examples of IDL union syntax. They are accompanied by the resulting IDL generated C header file declarations, and show how applications must refer to the union constructs declared in the IDL. The first example shows a set of declarations for an encapsulated union. The union holds either of two structures, one containing UUIDs, the other unsigned integers.

typedef struct two_uuid_s_t {
uuid_t uuid1;
uuid_t uuid2;
} two_uuid_t;

typedef struct two_uint_s_t {
unsigned32 uint1;
unsigned32 uint2;
} two_uint_t;

typedef enum {
uuids,
uints
} union_contents;

typedef union switch (union_contents type){
case uuids:
two_uint_t integers;
case uints:
two_uuid_t ids;
} test_union_t;

The resulting IDL generated C header declarations look like as follows:

typedef struct two_uuid_s_t{
uuid_t uuid1;
uuid_t uuid2;
}two_uuid_t;

typedef struct two_uint_s_t{
unsigned32 uint1;
unsigned32 uint2;
}two_uint_t;

typedef enum{
uuids,
uints
}union_contents;

typedef struct{
union_contents type;
union {
/* case(s): 0 */
two_uint_t integers;
/* case(s): 1 */
two_uuid_t ids;
} tagged_union;
}test_union_t;

The IDL compiler packages the encapsulated union as a structure with the discriminant as the first member. To pass the union as an [in] or [in,out] parameter, the calling application must set the type field of this structure to either of the enumeration values integers or ids. To return the union as an [out] or [in,out] parameter, the callee must similarly be sure that the value of the type field is correctly set. To discover which data type was marshalled, the recipient can check the value of the type field.

The following is an example of nonencapsulated union usage. The .idl declaration is as follows:

typedef
[switch_type(long)] union {
[case (1,3)] float a_float;
[case (2)] short b_short;
[default]; /* An empty arm */
} n_e_union_t;

The C header declaration of the nonencapsulated union generated by the IDL compiler is as follows:

typedef
union {
float a_float;
short b_short;
} n_e_union_t;

In this case, the discriminant must be separately declared in order for the union to be marshalled. The IDL [switch_is] attribute identifies the discriminant for an instance of the declared union type. Two examples of such .idl declarations follow:

/*
* A structure that includes the union declared above and a member
* that is used as the discriminant. This structure can be passed
* as an RPC parameter.
*/

typedef
struct {
long a;
[switch_is(a)] n_e_union_t b;
} a_struct;

/*
* An operation declaration that passes the declared union type along
* with a discriminant.
*/

void op1 (
[in] handle_t h,
[in, switch_is (s)] n_e_union_t u,
[in] long s
);