Correct byte alignment ensures that data used with an API is correct. Byte alignment is also essential when APIs are used to retrieve and then print or display data.
When byte alignment is off, it causes the API to read the data at some point other than at the beginning of a record.
This program illustrates byte alignment while defining a structure. This is shown at (1). Four-byte alignment is required when using this program.
Variable-length records must begin on a 4-byte boundary. As shown at (1), the variable-length record CCSID_rec is not beginning on a 4-byte boundary. When the API accesses the CCSID_rec record, 4-byte alignment is forced by padding the first 3 bytes of the CCSID_rec between the replace field and the start of the CCSID_rec record. (2) shows that the variable-length record is not 4-byte aligned (the value is 13, which is not divisible by 4). The correct coding is shown at (3).
/***************************************************************** */ /* */ /*Program Name: PGM1 */ /* */ /*Program Language: ILE C */ /* */ /*Description: This program illustrates improper byte */ /* alignment when using variable length */ /* records. */ /* */ /* */ /*Header Files Included: <stdio.h> */ /* <signal.h> */ /* <string.h> */ /* <stdlib.h> */ /* <qusrgfa1.h> */ /* <qusec.h> */ /* <qliept.h> */ /* */ /* APIs Used: QusAddExitProgram - Add an exit program */ /* */ /********************************************************************/ /********************************************************************/ /* Includes */ /********************************************************************/ #include <stdio.h> #include <signal.h> #include <string.h> #include <stdlib.h> #include <qusrgfa1.h> #include <qusec.h> #include <qliept.h> /********************************************************************/ /* Structures */ /* */ /********************************************************************/ typedef struct { /* Error code */ Qus_EC_t ec_fields; char exception_data[100]; } error_code_struct; typedef struct { /* Exit program attribute keys*/ int num_rec; Qus_Vlen_Rec_4_t replace_rec; char replace; Qus_Vlen_Rec_4_t CCSID_rec; (1) int CCSID; Qus_Vlen_Rec_4_t desc_rec; char desc[50]; } addep_attributes; /********************************************************************/ /* */ /* main */ /* */ /********************************************************************/ int main() { error_code_struct error_code; addep_attributes attrib_keys; /******************************************************************/ /* Initialize the error code parameter. */ /******************************************************************/ error_code.ec_fields.Bytes_Provided=sizeof(error_code_struct); /******************************************************************/ /* Set the total number of exit program attributes that we are */ /* specifying on the call. We will let the API take the default */ /* for the attributes that we are not specifying. */ /******************************************************************/ attrib_keys.num_rec=3; /******************************************************************/ /* Set the values for the three attributes that we will be */ /* specifying: */ /* Replace exit program = 1 (CHAR(1) field) */ /* Exit program data CCSID = 37 (BIN(4) field) */ /* Exit program description='THIS IS A TEST EXIT PROGRAM' */ /* (CHAR(50) field) */ /* */ /* The structure for the exit program attributes defined above is */ /* as follows: */ /* */ /* typedef struct { */ /* int num_rec; */ /* Qus_Vlen_Rec_4_t replace_rec; */ /* char replace; */ /* Qus_Vlen_Rec_4_t CCSID_rec; */ /* int CCSID; */ /* Qus_Vlen_Rec_4_t desc_rec; */ /* char desc[50]; */ /* } addep_attributes; */ /* */ /* and the Qus_Vlen_Rec_4_t structure is defined in */ /* qus.h (included by qusrgfa1) as: */ /* */ /* typedef _Packed struct Qus_Vlen_Rec_4 { */ /* int Length_Vlen_Record; */ /* int Control_Key; */ /* int Length_Data; */ /* **char Data[];-> this field is supplied by */ /* the user */ /* } Qus_Vlen_Rec_4_t; */ /* */ /* This structure is mapped in bytes as follows: */ /* { */ /* BIN(4) - num_rec */ /* BIN(4) - length variable length record for replace key */ /* BIN(4) - replace key */ /* BIN(4) - length replace data */ /* CHAR(1) - replace data */ /* BIN(4) - length variable length record for CCSID key */ /* BIN(4) - CCSID key */ /* BIN(4) - length CCSID data */ /* BIN(4) - CCSID data */ /* BIN(4) - length variable length record for description */ /* key */ /* BIN(4) - description key */ /* BIN(4) - length description key */ /* CHAR(50) - description data */ /* } */ /* */ /******************************************************************/ attrib_keys.replace_rec.Length_Vlen_Record=13; (2) attrib_keys.replace_rec.Control_Key=4; attrib_keys.replace_rec.Length_Data=1; attrib_keys.replace='1'; attrib_keys.CCSID_rec.Length_Vlen_Record=16; attrib_keys.CCSID_rec.Control_Key=3; attrib_keys.CCSID_rec.Length_Data=4; attrib_keys.CCSID=37; attrib_keys.desc_rec.Length_Vlen_Record=39; attrib_keys.desc_rec.Control_Key=2; attrib_keys.desc_rec.Length_Data=27; memcpy(&attrib_keys.desc, "THIS IS A TEST EXIT PROGRAM",27); /******************************************************************/ /* Call the API to add the exit program. */ /******************************************************************/ QusAddExitProgram("EXAMPLE_EXIT_POINT ", "EXMP0100", 1, "EXAMPLEPGMEXAMPLELIB", "EXAMPLE EXIT PROGRAM DATA", 25, &attrib_keys, &error_code); if (error_code.ec_fields.Bytes_Available != 0) { printf("ATTEMPT TO ADD AN EXIT PROGRAM FAILED WITH EXCEPTION:%.7s", error_code.ec_fields.Exception_Id); exit(1); } } /* end program */
The following example program shows a CHAR(3) bytes reserved field being added to the structure to maintain 4-byte alignment as shown at (4). This corresponds to (1) in the incorrect coding example. The 3 reserved bytes are included in the length of the replace variable-length record. (3) shows the variable-length record is now 4-byte aligned (record length of 16 is divisible by 4). This corresponds to (2) in the incorrect coding example.
/********************************************************************/ /* */ /*Program Name: PGM2 */ /* */ /*Program Language: ILE C */ /* */ /*Description: This program illustrates proper byte */ /* alignment when using variable length */ /* records. */ /* */ /* */ /*Header Files Included: <stdio.h> */ /* <signal.h> */ /* <string.h> */ /* <stdlib.h> */ /* <qusrgfa1.h> */ /* <qusec.h> */ /* <qliept.h> */ /* */ /* APIs Used: QusAddExitProgram - Add an exit program */ /* */ /* */ /********************************************************************/ /* Includes */ /********************************************************************/ #include <stdio.h> #include <signal.h> #include <string.h> #include <stdlib.h> #include <qusrgfa1.h> #include <qusec.h> #include <qliept.h> /********************************************************************/ /* Structures */ /********************************************************************/ typedef struct { /* Error code */ Qus_EC_t ec_fields; char exception_data[100]; } error_code_struct; typedef struct { /* Exit program attribute keys*/ int num_rec; Qus_Vlen_Rec_4_t replace_rec; char replace; char Reserved[3]; (4) Qus_Vlen_Rec_4_t CCSID_rec; int CCSID; Qus_Vlen_Rec_4_t desc_rec; char desc[100]; } addep_attributes; /********************************************************************/ /* */ /* main */ /* */ /********************************************************************/ int main() { error_code_struct error_code; addep_attributes attrib_keys; /******************************************************************/ /* Initialize the error code parameter. */ /******************************************************************/ error_code.ec_fields.Bytes_Provided=sizeof(error_code_struct); /******************************************************************/ /* Set the total number of exit program attributes that we are */ /* specifying on the call. We will let the API take the default */ /* for the attributes that we are not specifying. */ /******************************************************************/ attrib_keys.num_rec=3; /******************************************************************/ /* Set the values for the three attributes that we will be */ /* specifying: */ /* Replace exit program = 1 (CHAR(1) field) */ /* Exit program data CCSID = 37 (BIN(4) field) */ /* Exit program description='THIS IS A TEST EXIT PROGRAM' */ /* (CHAR(50) field) */ /******************************************************************/ attrib_keys.replace_rec.Length_Vlen_Record=16; (3) attrib_keys.replace_rec.Control_Key=4; attrib_keys.replace_rec.Length_Data=1; attrib_keys.replace='1'; attrib_keys.CCSID_rec.Length_Vlen_Record=16; attrib_keys.CCSID_rec.Control_Key=3; attrib_keys.CCSID_rec.Length_Data=4; attrib_keys.CCSID=37; attrib_keys.desc_rec.Length_Vlen_Record=39; attrib_keys.desc_rec.Control_Key=2; attrib_keys.desc_rec.Length_Data=27; memcpy(&attrib_keys.desc,"THIS IS A TEST EXIT PROGRAM",27); /******************************************************************/ /* Call the API to add the exit program. */ /******************************************************************/ QusAddExitProgram("EXAMPLE_EXIT_POINT ", "EXMP0100", 1, "EXAMPLEPGMEXAMPLELIB", "EXAMPLE EXIT PROGRAM DATA", 25, &attrib_keys, &error_code); if (error_code.ec_fields.Bytes_Available != 0) { printf("ATTEMPT TO ADD AN EXIT PROGRAM FAILED WITH EXCEPTION: %.7s", error_code.ec_fields.Exception_Id); exit(1); } } /* end program */