gtpa2m29 | Application Programming |
Several header files are provided for TPF application programming. The header files perform the following functions:
The header file structure approach changed from TARGET(TPF) to be more aligned with the way standard C programs are written. TARGET(TPF) provides the following for the tpfeq.h header file:
Figure 17. tpfeq.h Header File for TARGET(TPF)
ISO-C provides the following for the tpfeq.h header file:
Figure 18. tpfeq.h Header File for ISO-C
In addition to the header files that the TPF system provides, you can create your own. This section gives you some general guidelines.
The following items belong in TPF header files:
The following items do not belong in TPF header files:
All data structures that have a corresponding assembler DSECT defined by
their own macro reside in their own header files.
If you are going to convert existing assembler data macros to C or C++
structures, you need to consider boundary alignment. Boundary alignment
is determined by how data types are stored. The following shows how
data types are stored and aligned by the C or C++ compiler:
Data Type | Memory Occupied | Alignment |
---|---|---|
char | 1 byte | byte |
int | 4 bytes | fullword |
short int | 2 bytes | halfword |
long int | 4 bytes | fullword |
float | 4 bytes | fullword |
double | 8 bytes | doubleword |
In C, using int, short int, long int, float, and double in data structures forces boundary alignment to the next boundary determined by the data type. When these data structures are coded in assembler, the boundaries can differ (unless the assembler version is coded to coincide with the C version). This is a serious problem because it can result in errors that are difficult to diagnose.
The header file structure of C programs is changed to handle C++. The following changes have been made:
??=ifndef __NAME_HEADER__ ??=ifdef __COMPILER_VER__ ??=pragma filetag("IBM-1047") ??=endif #define __NAME_HEADER__ 1
See TPF Programming Standards for an example of the C header prolog.
??=pragma margins(1,72) sequence(73,80)
#ifdef __cplusplus extern "C" { #endif /* C function prototypes */ #ifdef __cplusplus } #endif
#ifdef __cplusplus #define NULL 0 #else #define NULL ((void *) 0) #endif
#ifdef __cplusplus #pragma pack (packed) #else _Packed #endif struct { long int li1; char cc1; short int si1; long int li2; short int si2; char cc2; } mytest; #ifdef __cplusplus #pragma pack (reset) #endif
See the IBM C/C++ language reference on the System/390 platform used by your installation for more information about #pragma pack.
#ifdef __cplusplus extern "builtin" #else #pragma linkage(func_name,builtin)
The following items can be useful.
When you run the CDSECT tool, these are the recommended parameters:
CDSECT name(BITF0XL DEFSUB EQUATE(DEF) LOWERCASE SEQUENCE)
struct tpf_example { long int exam_long; /* Field one */ short int exam_short; /* Field two */ int : 16; /* Reserved for use by IBM */ long int exam_long1; /* Field three */ };
Use no more than 16-bit increments to declare unnamed bit fields. If more than 2 bytes (16 bits) are needed, then use as many instances of 16-bit declarations as necessary.
struct tpf_example { long int exam_long; /* Field one */ int : 16; /* Reserved for use by IBM */ int : 16; /* Reserved for use by IBM */ long int exam_long1; /* Field two */ }; struct tpf_example2 { long int exam_long; /* Field one */ char exam_long1; /* Field two */ int : 16; /* Reserved for use by IBM */ int : 8; /* Reserved for use by IBM */};
To take advantage of field characteristics with C addressability, here is a suggested use of pattern:
struct tpf_example { long int exam_long; /* long example */ short int exam_short; /* short example */ short int exam_short2; /* 2nd short example */ short int exam_short3; /* 3rd short example */ char exam_char; /* character example */ char exam_char2; /* 2nd character example */ };
instead of:
struct tpf_example { char exam_char; /* character example */ int : 8; /* Reserved for use by IBM */ short int exam_short; /* short example */ short int exam_short2; /* 2nd short example */ short int exam_short3; /* 3rd short example */ char exam_char2; /* 2nd character example */ int : 16; /* Reserved for use by IBM */ int : 8; /* Reserved for use by IBM */ long int exam_long; /* long example */ }
Even if you need to organize a structure by function, this convention still applies. A substructure is created to contain the function, and the fields in the substructure are ordered by their integral boundary alignment.
Programming Rule |
---|
When data is used by both C or C++ language and assembler language programs, define the storage consistently with C or C++ language and adapt the assembler language programs accordingly. |
When an int field is defined as a bit field, the C compiler does not align the field, unless there is an intervening 0-length field.
Example: Assume you have 3 bytes of characters, followed by an integer. In assembler, it might be coded as follows:
CHARS DS CL3 INTEGER DS XL4
Assuming the character variable started at displacement 0, the integer variable will start in location 3.
Assume the same structure is coded in C as follows:
char chars [3]; int integer;
The character variable will still start at displacement 0. However, the integer variable will start at displacement 4 because integer data types are aligned on fullword boundaries. To make the alignment of the C structure the same as the alignment of the assembler structure, code it as follows:
typedef _Packed struct { char chars[3] ; int integer ; } astruct ;
#pragma pack(packed) struct astruct { char chars[3]; int integer; }; #pragma pack(reset)
Following are some reminders and coding techniques that you will find helpful when working with header files: