Coding in C

Note the information in the following sections when coding IBM MQ programs in C.


Parameters of the MQI calls

Parameters that are input-only and of type MQHCONN, MQHOBJ, MQHMSG, or MQLONG are passed by value; for all other parameters, the address of the parameter is passed by value.

Not all parameters that are passed by address need to be specified every time a function is invoked. Where a particular parameter is not required, a null pointer can be specified as the parameter on the function invocation, in place of the address of the parameter data. Parameters for which this is possible are identified in the call descriptions.

No parameter is returned as the value of the function; in C terminology, this means that all functions return void.

The attributes of the function are defined by the MQENTRY macro variable; the value of this macro variable depends on the environment.


Parameters with undefined data type

The MQGET, MQPUT, and MQPUT1 functions each have a Buffer parameter that has an undefined data type. This parameter is used to send and receive the application's message data.

Parameters of this sort are shown in the C examples as arrays of MQBYTE. We can declare the parameters in this way, but it is typically more convenient to declare them as the structure that describes the layout of the data in the message. The function parameter is declared as a pointer-to-void, and so the address of any data can be specified as the parameter on the function invocation.


Data types

All data types are defined with the typedef statement.

For each data type, the corresponding pointer data type is also defined. The name of the pointer data type is the name of the elementary or structure data type prefixed with the letter P to denote a pointer. The attributes of the pointer are defined by the MQPOINTER macro variable; the value of this macro variable depends on the environment. The following code illustrates how to declare pointer data types:
#define MQPOINTER                   /* depends on environment */
...
typedef MQLONG  MQPOINTER PMQLONG;  /* pointer to MQLONG */
typedef MQMD   MQPOINTER PMQMD;     /* pointer to MQMD */


Manipulating binary strings

Strings of binary data are declared as one of the MQBYTEn data types.

Whenever you copy, compare, or set fields of this type, use the C functions memcpy, memcmp, or memset:
#include <string.h>
#include "cmqc.h"

MQMD MyMsgDesc;

memcpy(MyMsgDesc.MsgId,           /* set "MsgId" field to nulls    */
       MQMI_NONE,                 /* ...using named constant       */
       sizeof(MyMsgDesc.MsgId));

memset(MyMsgDesc.CorrelId,        /* set "CorrelId" field to nulls */
       0x00,                      /* ...using a different method   */
       sizeof(MQBYTE24));

Do not use the string functions strcpy, strcmp, strncpy, or strncmp because these do not work correctly with data declared as MQBYTE24.


Manipulating character strings

When the queue manager returns character data to the application, the queue manager always pads the character data with blanks to the defined length of the field. The queue manager does not return null-terminated strings, but we can use them in your input. Therefore, when copying, comparing, or concatenating such strings, use the string functions strncpy, strncmp, or strncat.

Do not use the string functions that require the string to be terminated by a null (strcpy, strcmp, and strcat). Also, do not use the function strlen to determine the length of the string; use instead the sizeof function to determine the length of the field.


Initial values for structures

The include file <cmqc.h> defines various macro variables that we can use to provide initial values for the structures when declaring instances of those structures. These macro variables have names of the form MQxxx_DEFAULT, where MQxxx represents the name of the structure. Use them like this:
MQMD   MyMsgDesc = {MQMD_DEFAULT};
MQPMO  MyPutOpts = {MQPMO_DEFAULT};
For some character fields, the MQI defines particular values that are valid (for example, for the StrucId fields or for the Format field in MQMD). For each of the valid values, two macro variables are provided:

  • One macro variable defines the value as a string with a length, excluding the implied null, that exactly matches the defined length of the field. For example, the symbol ࿢ represents a blank character:
    #define MQMD_STRUC_ID "MD࿢࿢"
    #define MQFMT_STRING "MQSTR࿢࿢࿢"
    
    Use this form with the memcpy and memcmp functions.
  • The other macro variable defines the value as an array of char; the name of this macro variable is the name of the string form suffixed with _ARRAY. For example:
    #define MQMD_STRUC_ID_ARRAY 'M','D','࿢','࿢'
    #define MQFMT_STRING_ARRAY 'M','Q','S','T','R','࿢','࿢','࿢'
    
    Use this form to initialize the field when an instance of the structure is declared with values different from those provided by the MQMD_DEFAULT macro variable.


Initial values for dynamic structures

When a variable number of instances of a structure are required, the instances are typically created in main storage obtained dynamically using the calloc or malloc functions.

To initialize the fields in such structures, the following technique is recommended:
  1. Declare an instance of the structure using the appropriate MQxxx_DEFAULT macro variable to initialize the structure. This instance becomes the model for other instances:
    MQMD ModelMsgDesc = {MQMD_DEFAULT};
                                      /* declare model instance */
    
    Code the static or auto keywords on the declaration to give the model instance static or dynamic lifetime, as required.
  2. Use the calloc or malloc functions to obtain storage for a dynamic instance of the structure:
    PMQMD InstancePtr;
    InstancePtr = malloc(sizeof(MQMD));
                                      /* get storage for dynamic instance */
    
  3. Use the memcpy function to copy the model instance to the dynamic instance:
    memcpy(InstancePtr,&ModelMsgDesc,sizeof(MQMD));
                                      /* initialize dynamic instance */
    


Use from C++

For the C++ programming language, the header files contain the following additional statements that are included only when a C++ compiler is used:
#ifdef __cplusplus
  extern "C" {
#endif

/* rest of header file */

#ifdef __cplusplus
  }
#endif