Pragmas: Difference between revisions
(→Notes) |
|||
Line 257: | Line 257: | ||
* The pointers declared type cannot be pointer to void; e.g., void *. This is considered an opaque pointer. | * The pointers declared type cannot be pointer to void; e.g., void *. This is considered an opaque pointer. | ||
* For additional information on scl_ptr, including constraints, refer to the section on scl_ptr in the [[Media:s2sSCLReferenceGuide.pdf|SCL Reference Guide]]. | * For additional information on scl_ptr, including constraints, refer to the section on scl_ptr in the [[Media:s2sSCLReferenceGuide.pdf|SCL Reference Guide]]. | ||
=== Examples === | === Examples === |
Revision as of 13:58, 6 July 2015
The Stride pragmas are designed to allow annotation of C language constructs in such a way as to identify and define messages, function calls, and test units so that they can be transparently intercepted and remoted.
For details regarding the supported pragmas refer to SCL Reference Guide document.
scl_function
The scl_function pragma allows the user to capture a function. When captured for the purpose of interception (intercept-able) the optional arguments are used to specify how the intercept should be executed.
Syntax
#pragma scl_function(function-name [,context, name-mangling, group-id])
Parameters | Type | Description |
function-name | Identifier | Name of the function to capture. |
context | String | Optional. Context in which the function is going to be intercepted. Possible values are "REFERENCE" - intercept at the function call (i.e. where the function is called) or "DEFINITION" - intercept at the function definition (i.e. where the function is implemented). |
name-mangling | String | Optional. Type of name mangling to be used when intercepted. Possible values are "EXPLICIT" or "IMPLICIT". If the context argument is defined the default will be IMPLICIT. Note that if EXPLICIT is set the srTEST_INTERCEPT(<function_name>)" macro is required. |
group-id | String | Optional. User defined identifier representing the group to which this function belongs when enabling interception. The default group-id is set to STRIDE_TEST_GROUP. |
Notes
- The function must be declared as a designator with external linkage.
- A compilation error is reported if an attempt is made to capture a function more than once.
Examples
Using the defaults for IMPLICIT and STRIDE_TEST_GROUP when capturing boo
int foo(int x);
void boo(void);
#pragma scl_function(foo)
#pragma scl_function(boo, "DEFINITION")
Setting a specific GROUP ID
void boo(void);
#pragma scl_function(boo, "DEFINITION", ''IMPLICIT'', ''MY_TEST_GROUP'')
scl_cast
Constraining is the transformation of a data type so that it behaves like another data type. There are two forms of constraining: type constraining and value constraining (see scl_values pragma).
Type constraining, as in the C language, has a source type and a destination type. The source type is the data type that is originally specified (e.g., written in the header file). The destination type is the data type into which the source type is being transformed.
The scl_cast pragma is used for type constraining. It would commonly be used to map enumerations to other types, or to map a void pointer. The STRIDE host environment treats the constrained (or casted) field as if it were the new type, but the original type size is maintained.
Syntax
The following form changes the type inside the specified container (the function or structure):
#pragma scl_cast(global-type-specifier, cast-type)
The following form changes the type globally:
#pragma scl_cast(container-specifier, field-specifier, cast-type)
Parameters | Type | Description |
container-specifier | String | Name of the container of the field to be cast |
field-specifier | String | Name of the field to be cast |
cast-type | String | Name of the new type for the cast result |
global-type-specifier | String | Name of the global type to be cast |
Notes
- scl_cast() can only be used to cast items that are of exactly the same size.
- scl_cast() can only be applied to the integral type and pointer type instances, or typedef names for integral types or pointer types. The type-specifier must designate a pointer type or integral type.
- scl_cast() can be used to cast a data item of type void* to a union type, if all members of the union are of type pointer.
- scl_cast() cannot be applied to bit fields.
- An error will result if scl_cast() is applied to a set of runtime values that intersects with the set of values explicitly specified by any pragma that has appeared earlier (by way of lexical position) in the source code. In other words, scl_cast() cannot be used to "cast away" information conveyed by previous pragmas. (Refer to section 1.2.16, Absolute Specifiers, in the SCL Reference Guide for a description and definition of runtime value sets.)
Examples
Example 1
int func(void *p);
#pragma scl_function(func)
#pragma scl_cast(func, p, int *)
Example 2
typedef unsigned int u32_t;
typedef enum
{
ONE = 1,
TWO = 2,
THREE = 3
} numbers_e;
// cast occurrences of u32_t to numbers_e
#pragma scl_cast(u32_t, numbers_e)
int func(u32_t x);
#pragma scl_function(func)
scl_conform
The scl_conform pragma allows the user to define a conformant array within a payload. The payload can be a C structure or a parameter declaration list. The conformant array must be the last item in the payload (e.g., the last field in the structure, or the last parameter in the declaration list). Because of this, only the payload name and the name of the size field in that payload are required. The SCL compiler automatically assumes the conformant array field within the specified payload.
NOTE: For an alternative use case of sized structure please look at scl_struct_sized pragma.
Syntax
#pragma scl_conform(name, size-name, max-size)
Parameters | Type | Description |
name | String | Name of the structure or function that encapsulates the conformant array
The following restrictions apply:
|
size-name | Member | Name of the structure field or function parameter that contains the size of the array
The following restrictions apply:
|
max-size | Integer | Maximum size of the conformant array |
Example
/* Constant defining the maximum array size */
#define MAX_BUFFER_SIZE 20
/* Structure defining a message payload with a conformant array */
/* The array field must be the last member in the payload */
typedef struct {
int f1;
short bufferSize;
char buffer[1];
} CmdPayload_t;
/* Use the scl_conform pragma to define the conformant arrays */
#pragma scl_conform( CmdPayload_t, bufferSize, MAX_BUFFER_SIZE )
See Also
- For additional information on scl_conform, including constraints, refer to the section on scl_conform in the SCL Reference Guide.
scl_ptr
The scl_ptr pragma is used to identify a pointer data type and assign it pointer-specific attributes, such as marshaling direction and memory usage.
Syntax
#pragma scl_ptr(type-name, direction, usage) #pragma scl_ptr(type-name, field-name, direction, usage)
Parameters | Type | Description |
type-name | Type | Name of the type that contains the pointer. The container type can be a structure, union, the pointer type itself, or a function. If the container type is a structure or union, the pointer is a member and the field-name must be specified. If the container type is a function, then the pointer is a parameter and the field-name must be specified. |
field-name [Optional] | Member | Name of the pointer field, which may be a member field contained within a structure/union, or a parameter in the ParameterList of a function. |
direction | String | Direction in which the pointer data is marshaled; refer to the Pointer Direction Table below. This affects read and write access to the pointer data. |
usage | String | Pointer usage indicator; refer to the Pointer Memory Usage Table below. |
Pointer Direction Table
Value | Meaning |
"IN" | Specifies that the pointer memory can be used only as input to the receiver of the pointer. The Owner of the interface may only consider this read-only memory. |
"OUT" | Specifies that the pointer memory can be used to output information. The memory is allocated by the User and only written to by the Owner. |
"INOUT" | Specifies that the pointer memory can be used as both input and output. The User may send in data when sending the command (or calling the function), and may read the Owner’s output upon receipt of the response (or return of the function). |
"RETURN" | Specifies that the pointer memory may be read by the User of the interface. The User may only consider this as read-only memory and must not free it. |
"INRETURN" | Specifies that the pointer memory is allocated by both user and owner. There is no single block of memory pointed to by an "INRETURN" pointer. Rather there is one block on the call (or message send) and a second block on the return (or completion of the two-way message). Thus the first block has the characteristics of an "IN" block and the second the characteristics of a "RETURN" block. |
Pointer Memory Usage Table
Value | Meaning |
"PRIVATE" | Pointer memory is private and may not be released by the Reader. |
"POOL" | Pointer memory is created from common pool and must be released by the Reader. |
Notes
- A compiler error will be reported if an pointer does not point to a fixed size type.
- Response payloads cannot use the "OUT" or "INOUT" direction.
- Pointers with "OUT" or "INOUT" direction cannot indicate POOL pointer usage.
- One-way messages (command and response) cannot have data that contains an "OUT" or "INOUT" Pointer.
- The pointers declared type cannot be pointer to void; e.g., void *. This is considered an opaque pointer.
- For additional information on scl_ptr, including constraints, refer to the section on scl_ptr in the SCL Reference Guide.
Examples
Two examples using the scl_ptr pragma are shown below:
- The first example uses the scl_ptr pragma to assign pointer attributes to a structure member and a parameter list member.
- The second example uses the scl_ptr pragma to assign pointer attributes to type definitions.
Example 1
/* Typedef defining a structure with a member of type pointer to char */
typedef struct
{
int f1;
char * f2;
}data_t;
/* Function prototype with an "INOUT" pointer of type data_t */
void modifyData( data_t * p );
/* Use the scl_function pragma to associate a SUID with the function ModifyData */
#pragma scl_function( modifyData )
/* Use the scl_ptr pragma to define the member f2 as a "RETURN" pointer */
#pragma scl_ptr( data_t.f2, "OUT", "PRIVATE" )
/* Use the scl_ptr pragma to define the parameter p as an "INOUT" pointer */
#pragma scl_ptr( modifyData.p, "INOUT", "PRIVATE" )
Example 2
/* Typedef defining a pointer as a status type */
typedef int * StatusCode;
/* Apply scl_ptr to the StatusCode type. It is always an "OUT" pointer type */
#pragma scl_ptr ( StatusCode, "OUT", "PRIVATE" );
/* Prototype defining a function that returns a pointer to the data structure */
void GetStatus( StatusCode outCode );
/* Mark getStatus as an SCL-compliant function */
#pragma scl_function ( GetStatus );
scl_ptr_flist
The scl_ptr_flist() pragma is used to specify the candidate functions that are available for a specific function pointer data type.
Syntax
#pragma scl_ptr_flist(type-name, default-name) #pragma scl_ptr_flist(type-name, field-name, default-name) #pragma scl_ptr_flist(type-name, candidate-1, candidate-2..n) #pragma scl_ptr_flist(type-name, field-name, candidate-1, candidate-2..n)
Parameters | Type | Description |
type-name | String | Name of the type that contains the function pointer |
field-name | Member | Name of the pointer member within the struct/union or in the parameter list of the function |
candidate-1 | String | Name of the candidate function |
candidate-2..n [Optional] | String | Optional name(s) of additional candidate function(s) |
default-name | Quoted string | Name to be assigned to the default function (quoted string) |
Notes
- The syntax shown in form 1 of 4 above should only be used when function pointers are part of the command payload.
- The syntax shown in form 2 of 4 above should only be used when returning function pointers.
- A function pointer data type as written in ANSI C merely specifies the format of the prototype. The format of the prototype is the data type of the return value and the datatypes of the parameters, if any. The scl_ptr_flist() pragma is therefore required by the SCL compiler to indicate which SCL-compatible interfaces are associated with a particular function pointer data type.
- When a payload contains a field that is a pointer to a function, it is possible that the receiver of such a payload may make a call using the value received. Because the set of possible functions that might be passed is very large, and because all remotable methods must be identified with a SUID, each such payload value be constrained to identify the specific set of functions that might be passed. These are referred to as the candidates. Each candidate must be known by its name. The scl_brew_class() and scl_ptr_flist() pragmas are used for constraining fields of type pointer to function in this way.
- Payload fields of type pointer to function that are not explicitly associated with a list of candidates are treated as if they have been declared as void *.
See Also
- For additional information on scl_ptr_flist(), including constraints, refer to the section on scl_ptr_flist() in the SCL Reference Guide.
scl_ptr_opaque
The scl_ptr_opaque pragma is used to specify a pointer data type as pointing to opaque data that should not be marshaled.
Syntax
#pragma scl_ptr_opaque(type-name) #pragma scl_ptr_opaque(type-name, field-name)
Parameters | Type | Description |
type-name | Type | Name of the type that contains the Pointer. The container type may be the name of a structure, a union, the pointer type itself, or a function. If the container type is a structure or a union, then the pointer is a member and the field-name must be specified. If the container type is a function, then the pointer is a parameter and the field-name must be specified. |
field-name [Optional] | Member | Name of the Pointer field, which may be a member field contained within a structure/union, or a parameter in the parameter list of a function. |
Notes
- An opaque pointer is a pointer that points to opaque data. This means that the receiver of the pointer may not examine the data being pointed to. The meaningful part of an opaque pointer is the pointer value itself, or the pointer address. Opaque pointer are often used for the passing of handles.
- A pointer of type void (i.e., void *) is by default an opaque pointer. No pragma may be applied to a void pointer.
Examples
Two examples using the scl_ptr_opaque pragma are shown below:
Example 1
The first example uses the scl_ptr_opaque pragma to declare a structure member and a parameter list member as an opaque pointer.
// Typedef defining a structure with a member of type pointer to char //
typedef struct
{
int f1;
char * f2;
}data_t;
// Function prototype with an INOUT pointer of type data_t //
void modifyData( data_t * p );
// Use the scl_function pragma to associate a SUID with the function ModifyData //
#pragma scl_function( modifyData )
// Use the scl_ptr_opaque pragma to define the member f2 as opaque //
#pragma scl_ptr_opaque( data_t.f2 )
// Use the scl_ptr_opaque pragma to define the parameter p as opaque //
#pragma scl_ptr_opaque( modifyData.p )
Example 2
The second example uses the scl_ptr_opaque pragma to declare pointer type definitions as opaque.
// Typedef defining a structure with two members //
typedef struct
{
int f1;
char f2;
}data_t;
// Typedef defining a pointer to the data strucure //
typedef data_t * pointerToData;
// Prototype defining a function that returns a pointer to the data structure //
data_t * getData( void );
// Use the scl_ptr_opaque pragma to define the type pointerToData as opaque //
#pragma scl_ptr_opaque( pointerToData )
// Use the scl_function pragma to associate a SUID with the function "getData" //
#pragma scl_function( getData )
// Use the scl_ptr pragma to define "getData" return value as opaque pointer //
#pragma scl_ptr_opaque( getData )
See Also
For additional information on scl_ptr_opaque, including constraints, refer to the section on scl_ptr_opaque in the SCL Reference Guide.
scl_ptr_sized
The scl_ptr_sized pragma is used to identify a pointer data type, and assign to it attributes that are used to point to a series of elements allocated in contiguous memory. The pragma also assigns additional attributes, such as marshaling direction and memory usage.
Syntax
#pragma scl_ptr_sized(type-name, direction, usage, max-size) #pragma scl_ptr_sized(type-name, direction, usage, max-size, size-field-name) #pragma scl_ptr_sized(type-name, field-name, direction, usage, max-size) #pragma scl_ptr_sized(type-name, field-name, direction, usage, max-size, size-field-name)
Parameters | Type | Description |
type-name | Type | Name of the type that contains the pointer. The container type can be a structure, union, the pointer type itself, or a function. If the container type is a structure or union, the pointer is a member and the field-name must be specified. If the container type is a function, then the pointer is a parameter and the field-name must be specified. |
field-name [Optional] | Member | Name of the pointer field, which may be a member field contained within a structure/union, or a parameter in the parameter list of a function. |
direction | String | Direction in which the pointer data is marshaled; refer to the Pointer Direction Table below. This affects read and write access to the pointer data. |
usage | String | Pointer usage indicator; refer to the Pointer Memory Usage Table below. |
max-size | Integer | An integer constant that specifies the maximum number of elements pointed to. |
size-field-name | Member | The name of the field that specifies the current number of elements pointed to. |
Pointer Direction Table
Value | Meaning |
"IN" | Specifies that the pointer memory can be used only as input to the receiver of the pointer. The Owner of the interface may only consider this read-only memory. |
"OUT" | Specifies that the pointer memory can be used to output information. The memory is allocated by the User and only written to by the Owner. |
"INOUT" | Specifies that the pointer memory can be used as both input and output. The User may send in data when sending the command (or calling the function), and may read the Owner’s output upon receipt of the response (or return of the function). |
"RETURN" | Specifies that the pointer memory may be read by the User of the interface. The User may only consider this as read-only memory and must not free it. |
"INRETURN" | Specifies that the pointer memory is allocated by both user and owner. There is no single block of memory pointed to by an "INRETURN" pointer. Rather there is one block on the call (or message send) and a second block on the return (or completion of the two-way message). Thus the first block has the characteristics of an "IN" block and the second the characteristics of a "RETURN" block. |
Pointer Memory Usage Table
Value | Meaning |
"PRIVATE" | Pointer memory is private and may not be released by the Reader. |
"POOL" | Pointer memory is created from common pool and must be released by the Reader. |
Notes
- A sized pointer is a pointer to one or more elements of data. There are two types of sized pointers:
- Fixed-sized always points to the same number of elements as specified by max-size.
- Variable-sized points to a variable number of elements. The number of elements currently pointed to is indicated by size-field-name, which must be of type integer.
- If the sized pointer is "IN", then size-field-name can be a non-pointer integer type; otherwise it must be a single pointer. In either case, the parameter size-field-name must have the same direction as its associated-sized pointer.
- The type of the pointer cannot be pointer to void; e.g. void *. This is considered an opaque pointer.
Error Conditions
- A compiler error will be reported if a pointer does not point to a fixed size type.
- Sized pointers cannot use the "INOUT" direction.
- Response payloads cannot use the "OUT" or "INOUT" direction.
- Pointers with "OUT" or "INOUT" direction cannot indicate "POOL" pointer usage.
- One-way messages (command and response) cannot have data that contains an "OUT" or "INOUT" pointer.
Examples
This example uses the scl_ptr_sized pragma to assign pointer attributes to a parameter list member.
/* Constant defining the maximum buffer size */
#define MAX_BUFFER_SIZE 256
/* Function prototype with a sized IN pointer of type char */
void MemWrite( char * buffer, int size );
/* Function prototype with a sized OUT pointer of type char */
void MemRead ( char * buffer, int size );
/* Use the scl_function pragma to define the function prototypes */
#pragma scl_function(MemWrite)
#pragma scl_function(MemRead)
/* Use the scl_ptr_sized pragma to specify the attributes for the sized pointers */
/* Direction = "IN", memory usage = "PRIVATE", max size = 256, size field name = "size" */
#pragma scl_ptr_sized(MemWrite, buffer, "IN", "PRIVATE", MAX_BUFFER_SIZE, size)
/* Direction = "OUT", memory usage = "PRIVATE", max size = 256, size field name = "size" */
#pragma scl_ptr_sized(MemRead, buffer, "OUT", "PRIVATE", MAX_BUFFER_SIZE, size)
See Also
For additional information on scl_ptr_sized, including constraints, refer to the SCL Reference Guide.
scl_struct_sized
The scl_struct_sized pragma is used to identify a sized structure. A sized structure is a C programming convention for representing a structure whose size is variable and defined by one of the members of the structure. This pragma is infrequently used, but must be used, whenever the programmer defined size does not match the C language size of the structure (as calculated by the sizeof macro).
NOTE: For an alternative use case of sized structure please look at scl_conform pragma.
Syntax
#pragma scl_struct_sized(type-name, size-field)
Parameters | Type | Description |
type-name | Structure Type | Identifies a structure type or structure instance whose runtime size is not the same as its C language size and contains a field whose value is the runtime size.
The following restrictions apply:
|
size-field | Member | Identifies a field within the sized structure whose value determines the actual runtime size of the structure. The following restrictions apply:
|
Examples
Example 1
This example shows the declaration for a simple sized struct.
typedef struct {
int size;
int someJunk;
int moreJunk;
} SimpleSizedStruct;
#ifdef _SCL
#pragma scl_struct_sized(SimpleSizedStruct, size)
#endif
Example 2
This example shows the declaration of a sized struct containing a variable length array whose actual length is proportional to the value of the size field. In this case the array bound is declared as 1, but by convention is really controlled by the value of the size field.
typedef struct {
int size;
int someJunk;
int ary[1]; // variable length array whose length depends on the size
} ConformantArraySizedStruct;
#ifdef _SCL
#pragma scl_struct_sized(ConformantArraySizedStruct, size)
#endif
See Also
- For additional information on scl_struct_sized, including constraints, refer to the section on scl_struct_sized in the SCL Reference Guide.
scl_union
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.
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.
scl_union_activate
The scl_union_activate pragma provides a means to map discriminant values to specific union members. It can only apply to discriminated unions that have been identified by the scl_union pragma.
A single scl_union_activate pragma prescribes the set of values for the discriminant and the member that is active for those values.
Syntax
#pragma scl_union_activate(container-specifier, union-member-specifier, constant-value-list)
Parameters | Type | Description |
container-specifier | Type | Name of the structure encapsulating the union |
union-member-specifier | Member | The active member of the union |
constant-value-list | Integer constant expression list | List of the constant expressions that the discriminant takes on to activate the union member identified in this pragma |
Notes
- The discriminant field use in scl_union_activate must have already been identified with the scl_union pragma.
Examples
Refer to the following scl_union pragma examples of the scl_union_activate pragma:
- Explicit mapping: Discriminant values are explicitly mapped to active union members using scl_union_activate().
- Explicit mapping of multiple discriminant values to a single active member.
- Unmapped discriminant values indicating no member is active.
- Discriminant values defined by macros.
See Also
- For additional information on the scl_union_activate pragma, including constraints, refer to the section on scl_union_activate in the SCL Reference Guide.
scl_values
The scl_values pragma allows a data item to be constrained to a particular set of values.
Syntax
#pragma scl_values(global-type-specifier, values-type) #pragma scl_values(container-specifier, field-specifier, values-type) #pragma scl_values(container-specifier, field-specifier, values-value-1, values-value-2..n) #pragma scl_values(global-type-specifier, values-value-1, values-value-2..n)
Parameters | Type | Description |
global-specifier | String | Name of the global type to be constrained. |
values-type | String | Name of the type that enumerates the range of values to which the data item is constrained. |
container-specifier | String | Partial identification of the field to be constrained. The container_specifier in combination with the field_specifier completely identify the field to be constrained. |
field-specifier | String | Together with the container specifier, completes the identity of the field whose values are to be constrained. |
values-value-1 | Constant expression | First constant expression to which the data item's value will be constrained. |
values-value-2..n [Optional] | Constant expression list | Optional second and subsequent constant expressions, adding to the set of values to which the data item's value will be constrained. These expressions must be comma separated. |
Notes
- The scl_values pragma may only be applied to items that are of integral type (e.g., signed/unsigned char, short, int, and long), and pointers that have had the scl_ptr_opaque pragma applied to them.
- Each value in the values list is assigned both a symbolic name and an integral value. The symbolic name is:
- The macro name if the value is defined by a macro (the macro name must be a non-parameterized macro).
- The enumerated constant name if the value is an enumeration constant.
- If the constant is not a simple macro name or enumerated constant name (i.e., it is some kind of expression) then the name is the constant expressed as a decimal number, including its sign if the value is negative.
- Two values in the number-list may not have the same symbolic name.
- scl_values() does not change the underlying type of the instances to which it is applied. If those instances are referenced by other pragmas, the type is unaffected; however, the instances will have constrained values.
Examples
Example 1: Integer field constrained to enumeration values
typedef enum {
RED,
GREEN,
BLUE
} COLOR;
int f(int x);
#pragma scl_function(f)
#pragma scl_values(f.x, COLOR)
Example 2: Integer field constrained to a specific set of integer values
#define FIRST 23
#define SECOND 44
#define THIRD 50
#define FOURTH -5
int f(int x);
#pragma scl_function(f)
#pragma scl_values(f.x, FIRST, SECOND, THIRD, FOURTH)
See Also
- For additional information on the scl_values pragma, including constraints, refer to the section on scl_values in the SCL Reference Guide.