![]() |
![]() |
![]() |
![]() |
![]() |
C Specific Package ctypes
IBM Rational offers a special package ctypes that contains data types and generators that match C. It is described in detail in The ADT Library. The ctypes package should be used in the following cases:
- if you want to use pointers in SDL
- if you need a data type that matches some specific C type (for example short int) for which there is no corresponding SDL sort.
- if you use C headers directly in SDL In this case package ctypes must be used.
The tables below list the data types and generators in ctypes and their C counterparts.
ShortInt short int LongInt long int UnsignedShortInt unsigned short int UnsignedInt unsigned int UnsignedLongInt unsigned long int Float float Charstar char * Voidstar void * Voidstarstar void **
Carray C array, i.e. [] Ref C pointer, i.e. *The rest of this section explains how these data types and generators can be used in SDL.
Different Int Types and Float
ShortInt, LongInt, UnsignedShortInt, UnsignedInt, UnsignedLongInt are all defined as syntypes of Integer, so from an SDL point of view, these data types are really the same, and the normal Integer operators can be used on these types. The only difference is that the code that is generated for these types is different. Float is defined as a syntype of Real.
Charstar, Voidstar, Voidstarstar
Charstar represents character strings (i.e. char *) in C. Charstar is not the same as the SDL predefined type Charstring! Charstar is useful when accessing C functions and data types that use char *. In other cases it is better to use Charstring instead (see also Charstring). Conversion operators between Charstar and Charstring are available (see below).
Voidstar corresponds to void * in C. This type should only be used when accessing C functions that have void * parameters, or that return void * (in which case it is advised to "cast" the result directly to another type).
Voidstarstar corresponds to void ** in C. This type is used in combination with the Free procedure described in Using Pointers in SDL. In rare cases this type is also needed to access C functions.
The following conversion operators in ctypes are useful:
cstar2cstring : Charstar -> CharString;cstring2cstar : CharString -> Charstar;cstar2vstar : Charstar -> Voidstar;vstar2cstar : Voidstar -> Charstar;cstar2vstarstar : Charstar -> Voidstarstar;These operators have the following behavior:
- cstar2cstring:
Converts a C string to an SDL Charstring. For example if variable v of type Charstar contains the C string "hello world", then cstar2cstring(v) = 'hello world'.- cstring2cstar:
Converts an SDL Charstring to a C string, i.e. the opposite of cstar2cstring.- cstar2vstar:
Converts a Charstar to a Voidstar. This operator is sometimes useful when calling C functions with void * parameters.- vstar2cstar:
Converts a Voidstar to a Charstar. This operator can for example be used if a C function returns void *, but the result should be "casted" to a char *.The Carray Generator
The generator Carray in package ctypes is useful to define arrays that have the same properties as C arrays. Carray takes two generator parameters; an integer value and a component sort.
Example 33 : Carray instantiation
newtype IntArr Carray(10, Integer)endnewtype;The defined type IntArr is an array of 10 integers with indices 0 to 9, corresponding to the C type
typedef int IntArr[10];Two operators are available on instantiations of Carray; modify! to change one element of the array, and extract! to get the value of one element in the array. These operators are used in the same way as in normal SDL arrays, see Array. There is no (. ... .) notation provided for denoting values of whole CArrays.
modify! : Carray, Integer, Itemsort -> Carray;extract! : Carray, Integer -> Itemsort;Example 34 : Use of Carray in SDL
DCL v IntArr, i Integer;TASK v(0) := 3; /* modifies one element */TASK i := v(9); /* extracts one element */If a C array is used as parameter of an operator, it will be passed by address, just as in C. This makes it possible to write operators that change the contents of the actual parameters. In standard SDL this would not be possible.
The Ref Generator
The generator Ref in package ctypes is used to define pointer types. The following example illustrates how to use this generator.
Example 35 : Defining a pointer type
newtype ptr Ref(Integer)endnewtype;The sort ptr is a pointer to Integer.
Standard SDL has no pointer types. Pointers have properties that cannot be defined in normal SDL. Therefore they should be used very carefully. Before explaining how to use the Ref generator, it is worthwhile to list some of the dangers of using pointers in SDL.
Pointers Will Lead to Data Inconsistency
If more than one process can read/write to the same memory location by means of pointers, data inconsistency can and will occur! Some examples:
- In a flight reservation system there is one seat left, and two reservation requests come in simultaneously. If pointers were used to check the availability of seats, both requests might be approved! In literature this is called the "writers-writers problem".
- A process may update some array variable. If at the same time another process tries to read the variable by means of a pointer to the array, the reading process may get a value were some elements of the array are "new" while other elements are "old", and the total result makes no sense. This is the classic "readers/writers problem".
Even though tools such as the SDL Simulator and SDL Explorer will be able to detect a number of errors regarding pointers, there are situations that cannot be detected with these tools! This is because the Explorer and Simulator assume a scheduling atomicity of at best one SDL symbol at a time. This may not hold in target operating systems where one process can be interrupted at any time (pre-emptive scheduling). If pointers are used, data is totally unprotected, and data inconsistency may occur, even though the Explorer did not discover any problems! All these problems can be avoided by using SDL constructs for accessing data, like remote procedures and signal exchange.
For the above stated reasons, NEVER PASS POINTERS TO ANOTHER PROCESS! Not in an output, not in a remote procedure call, not in a create, and not by exported/revealed variables!
And if you do not obey this rule anyway: after passing a pointer, release immediately the "old" pointer to prevent having several pointers to the same data area. For example (for some pointer p):
OUTPUT Sig(p) TO ...;TASK p := Null;Pointers Are Unpredictable
If you have an SDL system that always works except during demonstrations, then you have used pointers! Bugs with pointers may be very hard to discover, as a system may (accidentally) behave correctly for a long time, but then suddenly strange things may happen. Finding such bugs may take very long time; in rare cases you might not find them at all!
Pointers Do Not Work in Real Distributed Systems
If an SDL system is "really" distributed, i.e. where processes have their own memory space, it makes no sense to send a pointer to another process, as the receiving process will not be able to do anything with it. Therefore, by communicating pointers to other processes, limitations are posed on the architecture of the target implementation.
Pointers Are Not Portable
The Ref generator and its operators are completely IBM Rational-specific. It is highly unlikely that SDL systems using pointers will run on other SDL tools.
Using Pointers in SDL
If you still want to use pointers in SDL after all these warnings, this section explains how to do this. A pointer type created by the Ref generator always has a literal value Null (corresponds to NULL in C), which is also the default value. The literal Alloc is used for the dynamic creation of new memory. Examples are given later.
It is up to the user to keep track of all dynamically allocated data areas and to free them when they are no longer needed.
The following operators are available for Ref types:
"*>" : Ref, Itemsort -> Ref;"*>" : Ref -> Itemsort;"&" : Itemsort -> Ref;make! : Itemsort -> Ref;free : in/out Ref;"+" : Ref, Integer -> Ref;"-" : Ref, Integer -> Ref;vstar2ref : Voidstar -> Ref;ref2vstar : Ref -> Voidstar;ref2vstarstar : Ref -> Voidstarstar;Furthermore, the following procedure is defined:
procedure Free; fpar p Voidstarstar; external;These operators can be used in the following way:
- *> (postfix operator):
Gets/changes the contents of a pointer. This is a postfix operator, so p*> returns the contents of pointer p. In SDL terminology this is the extract and modify operators for pointers.- & (prefix operator):
Address-operator. This is a prefix operator, so &var returns a pointer to variable var.- make! or (. .)
This constructor allocates new memory and assigns the parameter to make to the newly allocated memory.- free
This operator takes a pointer variable, frees the memory it refers to and sets the pointer variable to Null.- +, -:
used to add/subtract an offset to/from an address. This can be useful to access arrays in C. These operators are defined as in C, e.g. if p is a pointer to some struct, then p+1 points to the next struct (not to byte p+1).- vstar2ref:
Converts Voidstar to another pointer type. Should only be used to "cast" the result of C functions that return a void *.- ref2vstar:
Converts a pointer to Voidstar. This is useful when calling C functions that have void * parameters.- ref2vstarstar:
Returns the address of the pointer as a void **. This operator is needed when calling the Free procedure.- Procedure Free: (NOTE: use free operator above instead)
This procedure is used to release memory that has previously been allocated with alloc. This procedure is only provided for backward compatibility, use the free operator described above instead.Example 36 : Use of the Ref operators
NEWTYPE ptr Ref(Integer)ENDNEWTYPE;DCL p ptr,i, j Integer;TASK p := alloc; /* creates dynamically a newinteger; p points at it *//* here it should be checked that p != Null */TASK p*> := 10; /* changes contents of p */CALL free(p); /* releases the integer */TASK p := (. 10 .); /* allocate and set to 10 */CALL free(p); /* releases the integer again */TASK p := &i; /* p now points to i */TASK p*> := 5; /* changes contents of p, i.e. alsoi is changed! */TASK j := p*>; /* gets contents of p (=5) */Using Linked Structures with Pointers
Pointers are useful when defining linked structures like lists or trees. In this section we give an example of a linked list containing integer values. Figure 43 shows an SDL fragment with data type definitions for a linked list, and part of a transition that actually builds a linked list. A list is represented by a pointer to an Item. Every Item contains a pointer next to the next item in the list. In the last item of the list, next = Null.
Figure 44 shows an SDL fragment where the sum of all elements in a list is computed. Note that this computation would never stop if there would be an element that points back in the list, just to illustrate how easy it is to make errors with pointers.
http://www.ibm.com/rational |
![]() |
![]() |
![]() |
![]() |