Porting C Projects to IBM i
This document provides information on things you need to be aware when compiling C code which main target platform is not IBM i.
C Headers
The C Headers for most standard functions can be found at QSYSINC/H.
Compiler Directive
Probably some things will be configured and/or defined different on the IBM i platform as on other platforms. To differentiate between the OS types compile directives can be used. The IBM i platform automatically defines __OS400__ which can be queried like this:
#if __OS400__ // IBM i platform #else // other platforms #endif
Endian Type
Some C code takes advantage of the endian type of the system and because of that it needs to know on what type of system it runs on when it comes to byte order. There are little endian and big endian types.
IBM i is a big endian type system.
See Wikipedia article about Endianness.
Include Files
Default include files (header files or copy books in RPG) are provided in the IFS at
/QIBM/include
Data Types
There is an excellent paper about converting C prototypes and data types to its RPG equivalent from Barbara Morris, IBM:
Boolean
C does not come with many types like other languages and there is no type bool or boolean. But as there is the need for a boolean type in many libraries they defined true (equivalent to *ON in RPG) and false (equivalent to *OFF in RPG) in their code.
#define true 1 #define false 0
IBM i provides these in their header file stdbool.h so you can include it like this
#include <stdbool.h>
size_t
size_t
is a type definition and resolved to an unsigned integer of 4-bytes on the IBM i platform. Thus you can declare it as follows
dcl-s length uns(10);
Variable Number of Parameters
C supports variable number of parameters for functions. This feature can be used by calling the functions va_arg, va_copy, va_start and va_end. IBM only recently has completed this set of functions as va_copy was not available on any release prior to OS release version 7.2.
See IBM Knowledge Center.
Structures and Pointers
The system will sometimes use more space for a structure than the space it is declared to use because the system will try to align it to a boundary 4, 8 or 16 bytes.
If a pointer is part of the structure and the P128 Data Model is used then a pointer is 16 byte large and needs to be aligned on a 16 byte boundary.
We are taking a string structure as an example:
struct string { const char * value; size_t length; };
size_t resolves to a 4 byte integer type and a pointer (with the P128 data model) occupies 16 bytes of memory. This results in 20 bytes. But if we use the sizeof C function we see that 32 bytes are occupied by the structure. So in RPG we need to pad it with another 12 bytes.
dcl-ds string qualified template; value pointer; length uns(10); dummy1 char(12); // to fill up the 16 byte to the next boundary end-ds;
In RPG the built-in function %size can be used to see how many bytes a data structure occupies.
To allow proper alignment of components, holes or padding may appear between any consecutive members in the structure layout.
Bitwise Shift Operator
« is the bitwise shift left operator which is often used to define constants like
#define MG_F_SEND_AND_CLOSE (1 << 10)
In the example the symbol MG_F_SEND_AND_CLOSE has the value 1024. The following constant could be defined
dcl-c MG_FLAG_SEND_AND_CLOSE 1024;
These constants are mostly used to be stacked into a single integer and the queried with bit operators like this
flags |= MG_F_SEND_AND_CLOSE; ... if (flags & MG_F_SEND_AND_CLOSE) { ... }
The equivalent in RPG would be
flags = %bitor(flags : MG_F_SEND_AND_CLOSE); ... if (%bitand(flags : MG_F_SEND_AND_CLOSE) = MG_F_SEND_AND_CLOSE); ... endif;
For more information on bitwise operators see Bitwise Operation on Wikipedia.
Pointer in Integers
In C you can do very tricky things but most of these things are not really compatible with most platform. Different platforms have f. e. different sizes for certain data types.
One of those tricks is to store a pointer in an integer. This will work on 32-bit systems as a pointer is 4 byte and an integer also occupies 4 bytes.
But on IBM i a pointer is 16 bytes (P128 data model) and an integer is just 4 bytes. This just won't work.
uname / utsname
In the Unix world there is the function uname
which returns a structure utsname
which has at least the following members:
char sysname[] name of this implementation of the operating system char nodename[] name of this node within an implementation-dependent communications network char release[] current release level of this implementation char version[] current version level of this release char machine[] name of the hardware type on which the system is running
IBM i doesn't support this by itself.
See https://pubs.opengroup.org/onlinepubs/7908799/xsh/sysutsname.h.html .
Numbers declared as Hex
C devs like to declare their numbers in hex instead of just writing the numbers.
#define UNQLITE_OPEN_CREATE 0x00000004
can be declared in RPG as
dcl-c UNQLITE_OPEN_CREATE 4;
And
#define UNQLITE_SYNC_FULL 0x00003
can be declared in RPG as
dcl-c UNQLITE_SYNC_FULL 3;
Contributors
- Mihael Schmidt