To share data between programs (or between procedures), you need to pass parameters which both programs can use to the called program or procedure. In C++, you use the linkage specification to tell the compiler which parameter passing convention to use on the external call.
When passing parameters from C++ to a different high-level language (HLL)
consider:
Each HLL has its own way of passing parameters. Parameters can be passed as:
C++ passes parameters in all three ways. For information on these styles, see Using Default Parameter Passing Styles .
Different HLLs support different ways of representing data. Pass only parameters which have a data type common to the calling and called program or procedure. If you are not sure of the exact format of the data that is passed to your program, you may specify to the users of your procedure that an operational descriptor can be passed to provide additional information regarding the format of the passed parameters. For more information, see and Using Operational Descriptors to Pass Parameters of Unknown Data Type.
Table 20 shows the effect of using different linkage types when
passing parameters:
Table 20. Effects of Various Linkage Specifications
Linkage | Name Mangled | Parameter Passing | Parameter Widening | Comments |
---|---|---|---|---|
"C++" | Yes | C++ | No | This is the default. |
"C" | No | C++ | Yes | Used to call a function (procedure) written in ILE C. |
"C nowiden" | No | C++ | No | Used to call a function (procedure) written in ILE C. |
"OS" | No | OS | Yes | Used to call an external program written in any OPM/EPM/ILE language. |
"OS nowiden" | No | OS | No | Used to call an external program written in any OPM/EPM/ILE language. |
"RPG" | No | OS | No | Used to call a procedure written in ILE RPG. Parameters with address types (pointer or reference) are passed by value directly. All other parameters are passed by value indirectly. |
"COBOL" | No | OS | No | Used to call a procedure written in ILE COBOL. Parameters with address types (pointer or reference) are passed by value directly. All other parameters are passed by value indirectly. |
"CL" | No | OS | No | Used to call a procedure written in ILE CL. Parameters with address types (pointer or reference) are passed by value directly. All other parameters are passed by value indirectly. |
"ILE" | No | OS | Yes | Used to call a procedure written in an ILE language. Identical to RPG, COBOL, and CL specifications. If the particular language in which the function was written is unknown to the programmer, use this linkage. If you have C code that uses the #pragma argument directive and you plan to port this code to C++ then use the extern "ILE" linkage specification. |
"ILE nowiden" | No | OS | No | Used to call a procedure written in an ILE language. |
"VREF" | No | OS | Yes | Used to call a procedure written in an ILE language. Parameters are passed by value indirectly. |
"VREF nowiden" | No | OS | No | Used to call a procedure written in an ILE language. Parameters are passed by value indirectly. |
The extern keyword followed by the string literals "RPG", "COBOL", or "CL" are used to specify that the function has "ILE" linkage. These string literals perform the same function as the #pragma argument directive in ILE C. The "VREF" linkage also performs the same as the VREF parameter on the #pragma argument directive.
Specifying an ILE, CL, COBOL, or RPG linkage for a function tells the compiler:
Specifying a VREF linkage is identical to specifying an ILE linkage except that pointer parameters are stored in a temporary variable and the address of the temporary variable is passed as the actual argument.
The extern specifier followed by the string-literal "OS" or the string-literal "OS nowiden" is used to declare external programs. These programs may then be called in the same way as a regular function.
When an OS linkage function is called from a C++ program, the compiler generates code and performs the following tasks in sequence:
If extern "OS nowiden" is used, then the parameters and return value passed between programs are not widened.
If a temporary variable is created for a structure, the temporary variable has the same structure and information as the struct parameter passed.
The program name that the C++ dynamic program calls must be in uppercase. You can use the #pragma map directive to map an internal identifier longer than 10 characters to an OS/400-compliant object name (10 characters or less) in your program. See Renaming Programs and Procedures.
The return code for the dynamic program call can be retrieved by declaring the program to return an integer:
extern "OS" int PGMNAME(void);
The value returned on the call is the return code for the dynamic program call. If the program being called is a C++ program, this return code can be accessed using the _LANGUAGE_RETURN_CODE macro defined in the header file <milib.h>. A C++ program returns four bytes in the _LANGUAGE_RETURN_CODE. If the program being called is an EPM or OPM program, this return code can be accessed using the iSeries Retrieve Job Attributes (RTVJOBA) command.
When a function is called from an OS linkage function pointer, the compiler generates the same code sequence it does when calling an OS linkage function.
Non-pointer arguments are passed by value reference, and changes made to the variables in the called program are not reflected in the calling C++ program.
Specifying C linkage for a function tells the compiler:
The extern keyword followed by the string-literal "C" or the string-literal "C nowiden" is used to specify that the function is declared to have "C" linkage instead of "C++" linkage.
When using the extern "literal" statement, consider that:
// Using the typedef declarations above void foo (OS); void foo (CPP); // undefined behavior, foo already declared
extern "C" void foo (char); // chars are widened in C // In another compilation unit we then have extern "C" void foo (char c) // this parameter is correctly widened { // implementation of foo (char); }
extern "OS" void FOOPGM (char); // declaration: OK extern "OS" void FOOPGM (char c) // definition: undefined behavior { // implementation of FOOPGM }
extern "OS" { typedef void (*fp) (char); } fp FOO;
The widening rules for all the linkage specifications shown in Table 20 are:
extern "OS" { int a1; } extern "OS" int a2;
Functions FOO1(), FOO2(), and FOO3() are all declared as OS linkage functions. Functions FOO1() and FOO2() are declared by using the declaration-list syntax. FOO3() is declared by using the simple declaration.
extern "OS" { void FOO1 (char, char *); void FOO2 (int, int *); } extern "OS" int FOO3 (double, double *);
To pass parameters between ILE C/C++ and other ILE languages, especially ILE C, ILE RPG, or ILE COBOL, you must ensure that the other procedure is set up to accept data by reference.
ILE C++ uses the same calling mechanisms for calling any ILE HLL program or procedure: extern linkage specification.
ILE C++ passes and receives parameters using three passing methods:
Other ILE languages may have different methods of passing data.
See Table 21.
Table 21. Default Argument Passing Style for ILE Programs
ILE HLL | Pass Argument | Receive Argument |
---|---|---|
ILE C | by value, directly or by reference | by value, directly or by reference |
ILE C++ | by value, directly or by value, indirectly or by reference | by value, directly or by reference |
ILE COBOL | by reference or by value, indirectly | by reference or by value, indirectly |
ILE RPG | by reference | by reference |
ILE CL | by reference | by reference |
Table 22 shows the common parameter passing methods for the ILE
procedures.
Table 22. Default Argument Passing Style for ILE Procedures
ILE HLL | Pass Argument | Receive Argument |
---|---|---|
ILE C | by value, directly | by value, directly |
ILE C++ | by value, directly or by value, indirectly or by reference | by value, directly or by reference |
ILE COBOL | by reference or by value, indirectly | by reference |
ILE RPG | by reference | by reference |
ILE CL | by reference | by reference |
To pass a parameter to a procedure even though the data type is not precisely known to the called procedure you can use operational descriptors. Operational descriptors provide descriptive information to the called procedure regarding the form of the argument. This information allows the procedure to properly interpret the passed parameter. Use operational descriptors only when they are expected by the called procedure.
The C++ compiler supports operational descriptors for describing null-terminated strings. A character string in C++ is defined by: char string_name[n], char * string_name, or string-literal.
C++ defines a string as a contiguous sequence of characters terminated by and including the first null character. In another language, a string may be defined as consisting of a length specifier and a character sequence. When passing a string from a C++ function to a function written in another language, an operational descriptor can be provided with the argument to allow the called function to determine the length and type of the string being passed.
To use operational descriptors, you specify a #pragma descriptor directive in your source to identify functions whose arguments have operational descriptors. Operational descriptors are then built by the calling procedure and passed as hidden arguments to the called procedure. For the syntax, see WebSphere Development Studio: ILE C/C++ Compiler Reference.
The following examples illustrates the use of operational descriptors in ILE C/C++. They show:
The following figure shows an ILE C program that calls func1(). When the function func1() is called, the compiler generates operational descriptors for the three arguments that are specified on the call.
Figure 235. ILE C Source to Call a Function with Operational Descriptors
|
(C) Copyright IBM Corporation 1992, 2005. All Rights Reserved.