gtpa2m29Application Programming

TPF Header Files

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




Creating Your Own Header Files

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.

TPF Header Files and C++

The header file structure of C programs is changed to handle C++. The following changes have been made:

  1. The header file prolog will look as follows:
          ??=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.

  2. The #pragma margins directive is deleted from the code. The following example shows how the #pragma margins directive was previously used.
          ??=pragma margins(1,72) sequence(73,80)
    
  3. C linkage wrappers are added around all function prototypes, so all the existing C functions can be called from the C++ programs.
          #ifdef __cplusplus
              extern "C" {
          #endif
     
          /* C function prototypes */
     
          #ifdef __cplusplus
              }
          #endif
    
  4. The definition of NULL for C++ is added as follows:
          #ifdef __cplusplus
              #define NULL  0
          #else
              #define NULL  ((void *) 0)
          #endif
     
    
  5. The #pragma pack directive is supported for C++. The #pragma pack directive specifies the alignment roles to use for the structures, unions, and classes. The C++ compiler does not support the _Packed qualifier on the structure declaration. See the following example:
          #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.

  6. The #pragma linkage directive is not supported in C++ language. Therefore, change the #pragma linkage (func_name, builtin) directive in C to read:
    #ifdef __cplusplus
      extern "builtin"
    #else
      #pragma linkage(func_name,builtin)
    

More Useful Information

The following items can be useful.

  1. If you need to create a C structure from an existing BAL DSECT, use the CDSECT tool. The tool is documented in the user's guide for the particular IBM C or C++ compiler used by your installation. See "IBM High-Level Language Books" for a list of IBM C and C++ compiler publications for the System/390 platform. Using the CDSECT tool will aid in avoiding code language-porting errors.

    When you run the CDSECT tool, these are the recommended parameters:

       CDSECT name(BITF0XL DEFSUB EQUATE(DEF) LOWERCASE SEQUENCE)
    
  2. Indicate all storage generated for boundary alignment in a global/external structure by using a bit declaration and a comment.
    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             */
                       };
    
  3. Declare all reserved storage in a structure by using an unnamed bit declaration and a comment.

    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 */};
    
  4. Order the fields within a structure according to the basic integral boundary alignment (double, fullword, halfword, character) when creating new structures. This avoids boundary alignment problems which can cause code errors.

    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 ;
Note:
The struct has no tag; this prevents unintentional unpacked declaration of this struct. With the MVS and OS/390 C/C++ compilers, you may use #pragma pack():
    #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: