Navigation: Advanced Topics > Multi Language Programming >====== Resolving Data Types ====== | |
The Clarion language defines the data types BYTE, SHORT, USHORT, LONG, ULONG, SREAL, REAL, and STRING which map fairly easily to C, C++, Pascal, and Modula-2 equivalents. Clarion also defines DATE and TIME data types, and GROUP structures, which may be mapped to structures in each language. CSTRING and PSTRING data types are specifically provided by Clarion to simplify interfacing with external functions using C or Pascal conventions.
The DECIMAL, PDECIMAL, BFLOAT4, and BFLOAT8 types are not discussed because it is very unlikely that these types of variables will ever be used in C, C++, Pascal, or Modula-2 code. If data of any of these types does need to be passed to C, C++, Pascal, or Modula-2 code, simply assign the value to a REAL or SREAL variable and pass that to the function (data type conversion is automatically handled in Clarion by the assignment statement).
The table below gives a brief cross reference of the parameters types supported by the Clarion, C++ and Modula-2 compilers; as detailed, some parameters require additional pragma statements to work correctly. The Clarion SIGNED and UNSIGNED data types are equates that change type from LONG and ULONG.
Clarion | C++ | Modula-2 |
BYTE | unsigned char | BOOLEAN |
BYTE | unsigned char | SHORTCARD |
*BYTE | unsigned char * | var SHORTCARD |
USHORT | unsigned short | CARDINAL |
*USHORT | unsigned short * | var CARDINAL |
SHORT | short | INTEGER |
*SHORT | short * | var INTEGER |
LONG | long | LONGINT |
*LONG | long * | var LONGINT |
ULONG | unsigned long | LONGCARD |
*ULONG | unsigned long * | var LONGCARD |
SREAL | float | REAL |
*SREAL | float * | var REAL |
REAL | double | LONGREAL |
*REAL | double * | var LONGREAL |
STRING | can't pass by value | can't pass by value |
*STRING | unsigned int, char * | CARDINAL, ARRAY OF CHAR |
*STRING(with RAW) | char[] | var ARRAY OF CHAR |
*CSTRING(with RAW) | char[] or char * | var ARRAY OF CHAR |
*PSTRING | char[] or Char * | ARRAY OF CHAR |
GROUP | struct | var record type |
*GROUP(with RAW) | struct * | var record type |
*? | void far* | FarADDRESS |
UNSIGNED | unsigned int | |
SIGNED | int |
Clarion STRING variables are normally passed as two parameters: first, a UNSIGNED which contains the length of the data buffer; second, the address of the data. CSTRINGs and PSTRINGs are passed the same as STRINGs (as two parameters). The RAW attribute can be used in the Clarion prototype to pass only the address of the string data to external 3GL functions (Clarion language procedures do not need, or support, RAW).
C and C++ Data Type Equivalents
The following data type equivalents can be used with C or C++ code. These typedefs should appear in the .H header file referenced by the C or C++ code. The CLA prefix is used to avoid name clashes with third party libraries.
Typedef unsigned char CLABYTE;
Typedef short CLASHORT;
typedef unsigned short CLAUSHORT;
typedef long CLALONG;
typedef unsigned long CLAULONG;
typedef float CLASREAL;
typedef double CLAREAL;
Clarion DATE and TIME data types may be passed to C functions as a CLALONG, the CLADATE and CLATIME unions can then be used to resolve the elements of the date or time from the CLALONG value.
typedef union {
CLALONG n;
struct {
CLABYTE ucDay;
CLABYTE ucMonth;
CLAUSHORT usYear;
} s;
} CLADATE;
typedef union {
CLALONG n;
struct {
CLABYTE ucHund;
CLABYTE ucSecond;
CLABYTE ucMinute;
CLABYTE ucHour;
} s;
} CLATIME;
Because of Clarion's two-parameter method of passing STRINGs, the CLASTRING structure is useful for certain internal uses, but cannot be used to accept parameters from Clarion:
typedef struct {
char *pucString;
CLALONG usLen
} CLASTRING;
Clarion STRING variables are not NULL terminated, they are padded with spaces up to the length of the data buffer. The trailing spaces can be removed by using the Clarion CLIP procedure. The following code declares a STRING of 20 characters, assigns some data into it, and passes it as a parameter to a C or C++ function.
StringVar STRING(20)
CODE
StringVar = 'Hello World…'
C_Write_Function(StringVar)
The C or C++ function might be defined as:
extern void C_Write_Function(CLAUSHORT usLen, char *bData)
{ CLAUSHORT usNdx = 0;
while (usNdx <; usLen)
#ifdef cplusplus cout <;<; bData[usNdx++]; #else putchar(bData[usNdx++]); #endif } In the above example, usLen would have a value of 20 and bData would be padded with trailing spaces. This padding would be written to the screen by C_Write_Function(). Many C routines expect a string to be NULL terminated. To address this issue, Clarion provides the CSTRING data type. CSTRING variables are automatically NULL terminated when data is assigned to them. This makes it possible for existing C routines to operate on the data. A Clarion GROUP may be declared to contain related data. A group is roughly equivalent to a C or C++ struct. When passed as a parameter to a procedure, GROUPs are normally passed as three parameters: first, an UNSIGNED is passed which contains the size of the GROUP; second, the address of the GROUP structure; and third, the address of a buffer containing a type descriptor for the GROUP. The contents of the type descriptor are not discussed here and are subject to change in future versions of Clarion. GROUPs may be nested, and other GROUPs may be defined to assume the same structure as a previously declared GROUP. There are several forms of declaration for Clarion GROUPs: Struct1 GROUP ! Struct1 is defined as a GROUP ul1 ULONG ! containing two ULONG values ul2 ULONG END This form of definition reserves space for Struct1 and is equivalent to the C definition: struct { CLAULONG ul1; CLAULONG ul2; } Struct1; In the following example, the declaration of Struct2 declares a GROUP similar to that defined by Struct1, however no space is reserved. In practice there need not be any instances of Struct2 defined. Struct2 GROUP,TYPE ! Struct2 is declared as a GROUP ul3 ULONG ! containing two ULONG values ul4 ULONG END The corresponding C definition is: typedef struct { CLAULONG ul3; CLAULONG ul4; } Struct2 In the following example, the definitions of Struct3 and Struct4 define them to be LIKE(Struct2), i.e. of the same internal structure. In order to distinguish members of Struct3 and Struct4 from those of Struct2 the S3 and S4 prefixes must be used. Struct3 and Struct4 define instances of Struct2 (which is not necessarily defined anywhere). In both cases space is reserved. Struct3 LIKE(Struct2) Struct4 LIKE(Struct2) The corresponding C definitions are: typedef Struct2 Struct3; typedef Struct2 Struct4; Struct3 S3; Struct4 S4; Clarion GROUP declarations may be nested, for example: Struct5 GROUP,TYPE ! Struct5 is defined as a GROUP Struct6 GROUP ! containing a nested GROUP ul5 ULONG ul6 ULONG END END The equivalent C declaration is: typedef struct { struct { CLAULONG ul5; CLAULONG ul6; } Struct6; } Struct5; Modula-2 Data Type Equivalents The following data type equivalents are used with Modula-2 code. These definitions should appear in the Modula-2 definition module referenced by the Modula-2 code. These should be used to define parameter and return types of procedures that will be called from Clarion code. CONST BYTE ::= BYTE; SHORT ::= INTEGER (16-bit); USHORT ::= CARDINAL (16-bit); LONG ::= LONGINT; ULONG ::= LONGCARD; SREAL ::= REAL; REAL ::= LONGREAL; Clarion DATE and TIME data types may be passed to Modula-2 procedures as a LONG, the DATE and TIME RECORDs can then be used to resolve the elements of the date or time from the LONG value. DATE = RECORD CASE : BOOLEAN OF | TRUE: l : LONG; ELSE ucDay : BYTE; ucMonth : BYTE; usYear : SHORT; END END; TIME = RECORD CASE : BOOLEAN OF | TRUE: l : LONG; ELSE ucHund : BYTE; ucSecond : BYTE; ucMinute : BYTE; ucHour : BYTE; END END; Clarion STRINGs are passed in the same manner as Modula-2 open ARRAY OF CHAR parameters with the call(o_a_copy⇒off) pragma in effect (the length and the address of the string are passed). The following example code declares a string of 20 characters, assigns some data into it and passes it as a parameter to a Modula-2 procedure MAP MODULE('M2_Code') M2_Write_Proc(*STRING), NAME('M2_Code$M2_Write_Proc') END END StringVar STRING(20) CODE StringVar = 'Hello World…' M2_Write_Proc(StringVar) The Modula-2 procedure might be defined as: DEFINITION MODULE M2_Code; (*# save, call(o_a_copy⇒off) *) PROCEDURE M2_Write_Proc(StringVar: ARRAY OF CHAR); (*# restore *) END M2_Code. Note that Clarion STRINGs are not NULL terminated, they are padded with spaces up to the length of the data buffer. In the above example, StringVar would be padded with spaces up to a length of 20 characters. Variables of type CSTRING are automatically NULL terminated when data is assigned to them. This makes it possible for existing Modula-2 routines to operate on the data. A Clarion GROUP is roughly equivalent to a Modula-2 RECORD. There are several forms of declaration for Clarion GROUPs. The following conforms to the Modula-2 declaration of the DATE type above: DateType GROUP n LONG d GROUP,OVER(n) ucDay BYTE ucMonth BYTE usYear SHORT END END The OVER attribute is used to ensure that n and d occupy the same memory, the total size of the group is the size of the member n. When passed as parameters, GROUPs are normally passed as three parameters: first, an UNSIGNED is passed which contains the size of the GROUP; second, the address of the GROUP structure, and third, the address of a buffer containing a type descriptor for the GROUP. The contents of the type descriptor are not discussed here and are subject to change in future versions of Clarion. You may use the RAW attribute in your Clarion prototype for the Modula-2 procedure to instruct the compiler to pass only the address of the GROUP, otherwise you must define your Modula-2 procedure to take 2 extra parameters: MAP MODULE('M2_Code') M2_Proc1(*GROUP) M2_Proc2(*GROUP), RAW END END The corresponding Modula-2 definition module would contain: DEFINITION MODULE M2_Code; TYPE GROUP = RECORD (* Members *) END; PROCEDURE M2_Proc1(Len: USHORT; VAR Data: GROUP; TypeDesc: ADDRESS); PROCEDURE M2_Proc2(VAR Data: GROUP); END M2_Code. Pascal Data Type Equivalents The following data type equivalents can be used with Pascal code. These should be placed in the Pascal interface unit referenced by the Pascal code. These should be used to define parameter and return types of procedures that will be called from Clarion code. ALIAS SHORT = INT16; USHORT = INT16; LONG = INTEGER; ULONG = INTEGER; SREAL = SHORTREAL; Clarion DATE and TIME data types may be passed to Pascal procedures as a LONG, the DATE and TIME records can then be used to resolve the elements of the date or time from the LONG value. DATE = RECORD CASE BOOLEAN OF TRUE: (n : LONG); FALSE: (ucDay : BYTE; ucMonth : BYTE; usYear : SHORT); END; TIME = RECORD CASE BOOLEAN OF TRUE: (n : LONG); FALSE: (ucHund : BYTE; ucSecond : BYTE; ucMinute : BYTE; ucHour : BYTE); END; Because of Clarion's two parameter method of passing STRINGs, the STRING structure is useful for certain internal uses, but cannot be used to accept parameters from Clarion: TYPE STRING = RECORD usLen : USHORT; pucString : ^CHAR; END; Clarion PSTRINGs are passed by address in the same manner as Pascal STRING parameters with the call(s_copy⇒off) pragma in effect (the length and the address of the string are passed). The following example code declares a string of 20 characters, assigns some data into it, and passes it as a parameter to a Pascal procedure: MAP MODULE('Pas_Code') Pas_Write_Proc(*PSTRING), NAME('Pas_Code$Pas_Write_Proc') END END StringVar PSTRING(20) CODE StringVar = 'Hello World…' Pas_Write_Proc(StringVar) The Pascal procedure might be defined as: INTERFACE UNIT Pas_Code; (*# save, call(s_copy⇒off) *) PROCEDURE Pas_Write_Proc(StringVar: STRING[HIGH]); (*# restore *) END. A Clarion GROUP is roughly equivalent to a Pascal RECORD. There are several forms of declaration for Clarion GROUPs. The following duplicates the Pascal declaration of the DATE type above: DateType GROUP n LONG d GROUP,OVER(n) ucDay BYTE ucMonth BYTE usYear SHORT END END The OVER attribute is used to ensure that n and d occupy the same memory, the total size of the group is the size of the member n. When passed as parameters, GROUPs are normally passed as three parameters: first, a USHORT is passed which contains the size of the GROUP; second, the address of the GROUP structure; and third, the address of a buffer containing a type descriptor for the GROUP. The contents of the type descriptor are not discussed here and are subject to change in future versions of Clarion. You may use the RAW attribute in your Clarion prototype for the Pascal procedure to instruct the compiler to pass only the address of the GROUP, otherwise you must define your Pascal procedure to take 2 extra parameters: MAP MODULE('Pas_Code') Pas_Proc1(*GROUP) Pas_Proc2(*GROUP), RAW END END The corresponding Pascal interface unit might be: INTERFACE UNIT Pas_Code; TYPE GROUP = RECORD (* Members *) END; PROCEDURE Pas_Proc1(Len: USHORT; VAR Data: GROUP; VAR TypeDesc); PROCEDURE Pas_Proc2(VAR Data: GROUP); END.**