IBM Corp 1995
370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370 370
C/370(TM) Compiler News
July 1995 Volume 3 Number 3
Welcome to the July, 1995 Issue of the C/370 Newsletter
Reentrancy allows one or more users to share a single copy of a load module or to repeatedly use a load module without reloading it. Reentrancy has the following advantages:
A Reentrant program is structured so that it can be run by many users at the same time. The program is split into two parts:
Reentrant programs can be categorized by their Reentrancy type as follows:
Reentrancy is an advantage if there will be concurrent users of a program. These advantages become more apparent when the program is large. Even when a program is large and will have more than user at the same time, there are also these limitations to consider.
This section applies only to C/370 programs NOT running under MVS OpenEdition features since C++ and C/370 programs running under MVS OpenEdition are automatically prelinked.
If your program contains writable static, use the Language Environment prelinker to make your program Reentrant. This utility concatenates compile-time initialization information (for writable static) from one or more object modules into a single initialization unit. In the process, the writable static part is mapped.
To generate a reentrant load module, you follow these steps.
Note: If you are unsure about whether your program contains writable static, compile with the RENT option. Invoking the Language Environment prelinker with the MAP option and the object module as input, produces a prelinker map. Any writable static data in the object module appears in the writable static section of the map.
Certain program variables with the extern storage class may be constant and never written to. If this is the case, every user does not need to have a separate copy of these variables. In addition, there may be a need to share constant program variables between C/370 and another language.
As a programmer, you have some control over where objects with global names and string literals exist. You can use the #pragma variable(varname, NORENT) directive to specify that the memory for an object with a global name is to be in the code area rather than the writable static area.
/***********************************************************/ /* RATES is constant and in code area */ /***********************************************************/ #progma variable(RATES, NORENT) const float RATES[5] = { 1.0, 1.5, 2.25, 3.375, 5.0625} float totals[5];
In this example, the variable RATES exists in the executable code area because #pragma variable(RATES, NORENT) has been specified. The variable TOTALS exists in the writable static area. All users have their own copies of the array TOTALS, but the array RATES is shared among all users of the program.
When you specify #pragma variable(objname, NORENT) for a variable, and the program is to be Reentrant, you must ensure that this variable is never modified. Also you must include #pragma variable(objname, NORENT) in every source file where the object is referenced or defined; otherwise, the compiler will generate inconsistent addressing for the object, sometimes in the code area and sometimes in the writable static area.
Whether all string literals are distinct (non-overlapping) or modifiable is not defined by the ANSI C++ draft.
In C++/MVS(TM), the string literals exist in the code part by default, and are not modifiable if the code is Reentrant. In a large number of programs, string literals may be constant. In this case, every user does not need a separate copy of these strings.
By using the #pragma strings(writable) directive, you can ensure that the string literals for that compilation unit will exist in the writable static area and be modifiable. The following example illustrates how to make the string literals modifiable:
/************************************************************/ /* this example demonstrates how to make literals modifiable*/ #pragma strings(writable) #include <iostream.h> int main(void) { char * s s = 'wall\n"; // point to string literal *(S+3) = 'k'; // modify the string literal cout << s; // output "walk\n"
In this example program, the string "wall\n" will exist in the writable static area because #pragma strings(writable) is specified. The fourth character is modified.
For additional information on Reentrant code, see the Language Environment Programming Guide.
The object-oriented model for Input/Output consists of a set of C++ classes that make up the I/O Stream Class Library. This set of classes implements and manages stream buffers for input and output. Stream buffers are arrays of bytes where data is stored between the program and ultimate consumer (for output), or between the ultimate producer and the program (for input). Formatting of data is also done using stream buffers and manipulators.
There are two base classes, ios and streambuf, for which all other classes in the I/O Stream library are derived. The ios class and the classes derived from it are used to implement formatting of I/O and maintain error state information of stream buffers - implemented with the streambuf class.
To use the I/O Stream Library, include iostream.h header file in your program.
Although input and output are implemented with streams for both C and C++, the C++ I/O Stream Class Library provides the same facilities for input and output as C stdio.h. The I/O Stream Class library has the following advantages:
C++/MVS provides the following predefined streams:
All of the predefined streams are tied to cout. When you use cin, cerr, or clog, cout gets flushed so that the contents of cout are sent to the ultimate consumer.
All I/O to I/O Streams standard streams is accomplished with C/MVS(TM) standard streams:
When you redirect or intercept a C standard stream, the corresponding C++ I/O Stream standard stream is redirected along with it. This applies unless you redirect an I/O Stream standard stream.
C++/MVS I/O Stream Class Library file I/O is implemented in terms of C/MVS file I/O, and is, by default, buffered from it, with the exception of cerr, which is unit buffered (iso::unitbuf).. A filebuf object is associated with each ifstream, ofstream and fstream object. When filebuf is flushed, its contents are written to the underlying C stream, which has its own buffer.
The fstream, ifstream and ofstream class are used to specialize stream input and output for files.
For C++/MVS, overloaded fstream, ifstream and ofstream constructors, and open member functions, with an additional parameter, are provided so you can specify C/MVS fopen() You can use this additional parameter to specify any C/MVS fopen() mode value except type=record. If you choose to use a constructor without this additional parameter, you will get the default C/MVS fopen file characteristics.
Because I/O Streams I/O is based on C/MVS I/O, output to cout or clog may be interleaved with output to stdout or stderr, by explicitly flushing cout or clog before calling the C/MVS output function. Results of attempting to interleave output to cout or clog without explicitly flushing are undefined. Input to cin may be interleaved with input to stdin, on a line-by-line basis. Results of attempting to interleave on a per-character basis are undefined.
The following sample code illustrates use of C++/MVS predefined streams and interleaving of C/C++ Input and Output.
Program
// Example of interleaving I/O #include <stdio.h> #include <fstream.h> int main() { cout << "object: to illustrate interleaving I.O\n" << endl; printf( "interleaving output"); cout << "works with an (endl of line 1) \n" << flush; cout << "explicit flush of cout " << flush; printf( "(end of line 2) \n\n"); char string1 ??(80??) = ""; char string2 ??(80??) = ""; char string3 ??(80??) = ""; char* rc = NULL; cout << "type the following 3 lines:\n" "interleaving input\n" "on a per-line basis\n" "is supported\n" << endl; cin.getline(string1,80); rc = gets(string2); cin.getline(string3,80); cout << "\nstring1 is " << string1 << "\n" << "string2 is " << string2 << "\n" << "string3 is " << string3 << "\n" << endl; //The endl manipulator inserts a newline //character and calls flush(). char char1 = '\0'; char char2 = '\0'; char char3 = '\0'; cout << "type the following 2 lines.:\n" << "results of interleaving input on a per-\n" << "character basis are not defined\n" << endl; cin >> char1; char2 = (char) getchar(); cin >> char3; cout << "\nchar1 is " << char1 << "\n" << "char2 is " << char2 << "\n" << "char3 is " << char3 << "\n" << endl; }
Input/Output
// sample output (with user input shown with **) // and program output with //) // object: to illustrate interleaving I/O // interleaving outputworks with an (end of line 1) // explicit flush of cout (end of line 2) // type the following 3 lines: // interleaving input // on a per-line basis // is supported ** interleaving input ** on a per-line basis ** is supported // string1 is interleaving input // string2 is on a per-line basis // string3 is is supported // type the following 2 lines: // results of interleaving input on a per- // character basis are not defined ** results of interleaving input on a per- ** character basis are not defined // char1 is r // char2 is c // char3 is e
For more information on the classes available with the I/O Stream Class Library and how to use them, see the C++/MVS Class Library Reference and the C++/MVS Class Library User's Guide.
The new generation of C++ has arrived. IBM VisualAge C++ for OS/2, V3.0 takes C++ application development to new levels of productivity. Now, mission-critical , object-oriented applications are within easy reach with Visual Age C++'s powerful application "construction from parts" paradigm. VisualAge C++ delivers:
With VisualAge C++, application construction has never been easier. Even the most complex applications can be constructed from the large set of predefined parts from IBM Open Class. You can also create your own parts and import them easily to the visual builder. These parts can be assembled quickly and easily with the visual builder, and your application can be generated with the click of a button. Reuse is now real world!
The visual builder generates ANSI-compliant C++ source code that is compiled into a highly-optimized application. No performance compromise and a royalty-free runtime environment.
Now, make quick work of bringing existing relational data into the object world. The Data Access Class Builder visually maps DB2(TM) for OS/2 relational database tables into objects with a single click. All of the C++ and SQL code generation is done for you. Simply import these "data objects" into the visual builder and construct your application. An underlying set of class libraries handles the complexities of data access and CORBA-compliant persistent object storage.
IBM Open Class is a set of C++ class libraries that gives you an extensive choice of building blocks for creating your applications. While Open Class handles the complexity of low-level APIs, you can focus on your application. Because Open Class is the foundation for the visual builder, you become productive immediately by using real objects directly from the builder. You spend more time building applications, not learning the complexities of object-oriented designs and class libraries.
You can also create your own custom objects and extend Open Class by using the extensive set of C++ programming tools integrated in VisualAge C++. With IBM Open Class, you have the flexibility of a consistent programming interface across a wide range of platforms including: OS/2, Warp, AIX®, and Sun Solaris(**). In the future, it is our intent to make VisualAge C++ available on MVS, OS/400®, Windows NT(**), Windows 95(**) and OS/2 for the PowerPC(TM). With IBM's C++ environments on these platforms, you can code your application once and deploy it anywhere in your enterprise.
VisualAge C++ sets the pace with a complete set of integrated tools built for the C++ developer.
WorkFrame gives you a productive place to create and manage your C++ code. With "Easy Options", you build code in either debug, browse or optimized modes - without having to manage compiler options manually. With WorkFrame, you move naturally from tool to tool. In addition, Project Smarts gives you automatically-configured skeleton applications to start your coding immediately.
Explore and understand your code and class libraries quickly with the VisualAge C++ browser. Use the QuickBrowse feature to get information on C++ code even exactly when you need it - even before you compile.
Get your application up-to-speed with two powerful tools. With the debugger's intuitive user interface, you can debug at the source level, set breakpoints, handle advanced C++ functions such as templates and exceptions and isolate difficult memory management bugs. Use the Performance Analyzer to fine tune your application's performance. Through graphical representations of trace information, you discover the hotspots and bottlenecks in your programs.
Editing source code is a snap using the syntax - highlighting editor. Because editors are a personal choice, this one can be customized to your way of working.
The 32-bit C/C++compiler delivers rock-solid code ready to meet the demands of your business.
With precompiled header files, you can expect fast compiles. A new 32-bit linker, built for C++, is up to three times faster than the previous version. C++ generates applications that are highly optimized for OS/2. In addition, code can be optimized for any Intel(**) processor from the i386 to the Pentium(**).
Now, you can generate SOM objects directly from familiar C++ syntax simply by turning on a compiler option. The compiler will also generate the corresponding Interface Definition Language(IDL) for interlanguage or Distributed SOM applications. In addition, you can browse and debug SOM objects with the VisualAge C++ tools. SOM objects can be imported to the visual builder so distributed object applications can be assembled quickly.
Come and talk to the developers of mainframe C/C++ at GUIDE in Boston, July 16-21 and at SHARE in Orlando, August 13-18. Check the appropriate calendar for session numbers. The sessions currently planned are:
The information processing business has never been more complicated. We're trying to deliver products and related tools to help you simplify it. Come and hear what changes we've made, and are making, with C and C++; learn how C/C++ for MVS/ESA works with other products; and, learn how you can leverage these powerful languages to satisfy your business needs across a variety of platforms.
C and C++ are known for their portability; however, the underlying operating systems are different and there may be changes to make to your applications to allow them to run on the mainframe. There are also a number of extensions to ANSI standards that could save you time and effort. If you're doing application porting to the mainframe, and want some coaching, please come and see us.
C and C++ have a number of capabilities that you can't always pick up on, except by using them. Since we use these languages and tools every day ourselves, we can show you real code to do what you need to do. There a number of 'tricks' to make your code run faster, as well as minimize maintenance costs.
These questions are culled from a variety of sources: from various question and answer databases, from customer calls, and from our own experiences. If you have a question you'd like answered, please send it to IBMMAIL(CAIBMRXZ) or inetc370 @ vnet.ibm.com. We'll answer your question and perhaps print it in the next newsletter.
Question- Demangling
I would like to know how the mangling/demangling works under the covers. Is there a piece of the compile or the linkage editor which looks and knows from a lookup table or other method which is the next number? Or is it simply a counter held in some place? How does it keep up with the original long name corresponding to the created short one -- is it using a table look-up, dictionary look-up or some other method?
Answer
The term 'demangling' refers to two different things.. mapping long names to short ones, and handling multiple instances of a function name, each of which accepts different parameter types.
Both the compiler and prelinker do the work. The compiler allows a long name to be put into the text deck, and the prelinker does the resolution from long names to short ones. It does this while exposed to all C objects at the same time (eg. if two module components are to be tied together, they must be prelinked together, regardless of the compilation setup or if a long variable name used in two different modules, can only be resolved correctly when those two modules are prelinked together.).
Under C++, the name demangler (CXXFILT) is available to 'demangle' a 'mangled' name. For more info, see the C++/MVS User's Guide.
The prelinker numbers the instances of long names and creates a name from that numbering, mapping the long name to the short one. A list of these mappings can be generated with prelinker option 'MAP'.
Question- Longname mapping
I want to be able to use a long-name naming convention to map to shorter named C external entry names. Example: External entry name GETDATE -- and I want to use a longer name ie....ACCTINGGETDATERTN to map to or convert to the shorter real entry point name. I thought a new function in C/370 called map pragma's might help them with this.....
Answer
When processing longnames, the prelinker will do a highly unsophisticated mapping. It starts with @ST00001, as the first mapping, then adds 1 to the counter for each unique name. It is faster to go sequentially than it is to hash and maintain a collision chain.
The prelinker has access to all of the information in all text decks that are to be linked together, and can thus make use of this technique. If it didn't have all the information, then hashing would be required.
Question- Activating Debugging Tool Interface
How do I activate the debugging tool interface? I included the following lines in my c++ program, run the clist below, but no debugging window appeared. What did I do wrong?
#pragma options(test) #pragma runopts (execops)
CONTROL LIST CONLIST SYMLIST MSG ALLOC FI(INSPSAFE) DA(INSPECT.SAVE) REUSE SHR ALLOC FI(INSPLOG) DA(INSPECT.LOG) REUSE SHR ALLOC FI(INSPPREF) DA(INSPECT.PREFEREN) REUSE SHR CALL 'my.load.lib(BIO)' 'TRAP(ON) TEST(ALL)' FREE FI(INSPSAFE) FREE FI(INSPLOG) FREE FI(INSPPREF)
Answer
#pragma options and #pragma runopts aren't supported under C++.
Compile with the TEST option and run your program with the TEST option (in your example, you were already running with the TEST option). The #pragma runopts(execops) is not necessary, since EXECOPS is the default. If you want to control execops, use the compile-time option EXECOPS|NOEXECOPS.
Question- Normal Batch C program in CICS(TM)
How easy (or is it possible) to take a normal C program (no terminal I/O) and to compile it to CICS using C/370.
Will it work ?
Answer
Basic migration for non-CICS to CICS:
If your application fits within these boundaries, then you should be able to migrate.
Question- make and ar utilities
We were looking into using the 'make' and 'ar' utilities, but the documentation implies that they are part of Open Edition MVS (C++ User's Guide p. 178).
Is this true? Does this mean we have a compiler without a 'make' utility?
Answer
Correct. 'make' and 'ar' are part of OpenEdition, not C/370. No, we do not have any makefile function as part of our current products.
Question- Portable Class Lib for C++
I need a collection class library that is available for both MVS and HP-UX. One opinion out of IBM was that the Taligent library from HP would match the collection classes from IBM. An HP/Taligent engineer and I compared class and method semantics briefly and concluded the IBM and Taligent collection classes aren't compatible. Did we miss something? When will the Taligent libraries find their way into MVS? Has anyone attempted to port Rogue Wave's Tools.h++ to MVS?
Answer
Taligent libraries are being rolled into IBM Class over time. The rollout is over the course of a couple of years, as IBM Class expands. I have heard from people who have ported all but the template code for tools.h++ already onto C++/MVS. We have been in contact with the folks at Rogue Wave and are working with them in an attempt to label it as 'C++/MVS compatible' (or equivalent).
Question- Length of data in Storage
I have to write an application designed to run under several platforms (OS/2, MVS, AIX® and others). Application must provide access to files system (sequential, indexed and relative ) under these platforms, so I wrote a library which handles generic file access, and provides developers some Open functions, like SOPEN to open a sequential, Iopen to open an indexed data set, etc ...
Ideally to make a write to a file, developers code OWRITE(File descriptor,Record), and do not care about the length of the record. In my libraries, I don't know at run time the length of data in record, record is only a pointer to void. Do you know a function which return the length of data in storage at runtime. The sizeof function of C is only useful on compile time!
Answer
I think you're going to have to impose a limitation on your user: either they tell you the size, or put a delimiter on the buffer so that you can pick it off for yourself.
Question- Performance Tuning
We are in the process of performance tuning some of our applications which are written in AD/Cycle C/370. We have both batch jobs as well as CICS transactions.
We have a couple of questions regarding our tuning efforts.
Answer
Question- fetchable
Can load modules containing c++ code be fetchable?
Answer
Modules with C++ code can't be fetched. Use dllload() followed by dllqryfn()/dllqryvar() instead.
Question- Code Coverage Tool
I'd like to know if there is any tool available which allows to measure code coverage for C++ on MVS. Any hints are appreciated.
Answer
The debugger shipped with C/C++ for MVS/ESA has commands to get frequency analysis at the function or statement level.
Question- Batch Debugger
I need to execute a lot of testcases without user invention. This seems not to be possible if I use a debugger which must be invoked interactively. May I use the debugger in batch jobs?
Answer
Yes, the debugger shipped with C/C++ for MVS/ESA supports having a script file being read under MVS Batch, and using that instead of working interactively. You can use the script file under other environments as well. The TEST runtime option lets you specify the file you can read from. For example, the runtime option TEST(ALL,INSPIN,NOPROMPT,INSPPREF) would instruct the debugger to use the DDName INSPIN to get debug commands from, read preferences (like a profile, or config file) from the DDName INSPPREF, and not to prompt you. Also, you would want to allocate the DDName INSPLOG to point to a LRECL 72 RECFM F file - this is where the output of the Debug Tool commands will be written.
Question- C/370 Environments
What is the difference between a C/370 Preinitialization Environment and a Persistent C Environment? Which one performs better when a C function is called from an assembler language application?
Answer
'Persistent' allows assembler to call C routines, with or without the Library loaded (HOTL or HOTC). These routines must be non-main.
'Preinit' allows assembler to call C main() functions only, and supports the use of 'RENT' - 'persistent' does not.
Both interfaces allow you to repeatedly call C code while only setting up and taking down the environment once.
Under LE/370, 'Preinit' is extended to allow the execution of both main() and non-main() code, plus other features.
Question- Return statements
I generally like to have all C/370 modules compiled with the checkout option at some point near the end of the development cycle just to see what's going on. Additionally, some of our "C" code is developed on AIX and its an opportunity to take different look at the code.
My question is that based on the way the code was written the warning message EDC0833 Implicit return statement encountered is constantly generated. Is there a technical reason, performance or otherwise, why an explicit vs. implicit "return" makes a difference.
Answer
'implicit return' happens when we run out of code to execute and fall onto the final right brace of the routine. The situation is flagged because you may or may not have intended to take this sort of exit. "Proper" programming says that you should use exit() or return statement, and not allow your program to run off.
Question- Dilemma with certain Hex characters
Was wondering if anyone has run into this and figured out a way around it. I am using C on MVS and am fairly new to C but familiar with MVS.
Simplified, I am trying to read a file, count the records, and write out what I read. Both the file I am reading and the file I am writing has variable length records (no specific format nor record length). I do know the maximum possible record length. I don't care about the actual values of the data I read. The input can have valid hex data as follows: x'C1C200153CC1C2'
My problem is figuring out a way to read/write the x'15' (newline character - and probably other control values). I realize I probably can't use text I/O. The part I'm missing is how the MVS file system communicates to C as to what is a "record" in the MVS file (ie the length of that particular record). How many characters are in a single MVS file record.
Someone I spoke with suggested using the OPEN and READ primitives. The READ might return the number of bytes. However, I don't know what system libraries these might be in and therefore was unsuccessful in linking using these calls.
The output if not coming out looking like the input.... if I only had a way to tell how many "real" data bytes are in each record....
I currently have the following code:
#include <stdio.h> #include <stdlib.h> #define MAXLEN 100 FILE *infile; FILE *outfile; char *filename; fldata_t *info; unsigned char line[MAXLEN]; int count; main() { if ((infile=fopen("DD:INFILE", "rb")) == NULL) printf("Could not open data file-1\n"); else { outfile=fopen("DD.:OUTFILE", "ab,recfm=vb"); for (i=0; i < 5; i++) { fgets(line,MAXLEN,infile); for (count=0; count < MAXLEN; count++) { fputc(line[count],outfile); } } fputc('/n',outfile); } } }
Answer
If I understand you correctly what you want to do is copy the contents of one V(B) file to another VB file in such a way that the content (blanks, control chars etc) is not disrupted at all.
What you want to do is open the file "type=record". This is a binary mode - so control characters are ignored - with the special feature that it will only read in a maximum of 1 record on a read. type=record requires that you use fread/fwrite to read and write from the file.
If you are using the Language Environment 1.3 or 1.4 library or the C/370 2.2 library and you know you are not going to be repositioning (ftell, fseek, fgetpos, fsetpos, rewind in a file opened for something other than read ) you should also put "noseek" in second parameter of your fopen call. Noseek may give you a nice little performance boost. Noseek works - with less of an performance impact - on the other currently supported C libraries.
To change your code
#include <stdio.h> #include <stdlib.h> #define MAXLEN 100 FILE *infile; FILE *outfile; char *filename; fldata_t *info; unsigned char line[MAXLEN]; int count,reclen; main() { if ((infile=fopen("DD:INFILE","rb,type=record,noseek"))==NULL) printf("Could not open data file-1\n"); else { outfile=fopen("DD.:OUTFILE","ab,recfm=vb,type=record,noseek"); for (i=0; i < 5; i++) { reclen=fread(line,sizeof(char),MAXLEN,infile); fwrite(line,sizeof(char),MAXLEN,outfile); } }
And, if you wanted to get fancier, you could use fldata() on the file you open to check all the info about the file, such as record length, record format, etc.. That way, you can dynamically create a buffer to hold a record and (probably more importantly) you can check to make sure the DDname that was provided as input is what you expected (e.g. VB).
Question- Specifying high level qualifier in batch
I have a portable C program that runs on DOS, VM, and MVS. The program opens several files. An example of code that opens a file is fopen("router.ini", "r"). On DOS, the program will open the file ROUTER.INI. On VM, the program will open the ROUTER INI *. In TSO, the program opens the file "HLQ.ROUTER.INI" where HLQ is the high level qualifier. When I run the program on MVS in batch, my program doesn't successfully open the file. Apparently, the high level qualifier used is not the same as the file. I was wondering if there was a way to specify the high level qualifier to use for all files that are reference by my C program in batch. Thanks!
Answer
First, there are two ways to set up your header files in a reasonably portable manner:
For example, if your header files were in the datasets:
'TS36133.PROJ23.H' and 'TSPROJ.COMMON.H'you would specify your USERLIB as:
//SYSLIB DD DSN=TSPROJ.COMMON.H,DISP=SHR // DD DSN=TS36133.PROJ23.H,DISP=SHR
You may also want to put single quotes around the name of the file you want to fopen(), eg. fopen("'TS36133.ROUTER.INI'", "r") or use the TSO command PROFILE PREFIX(xxx) where xxx is the new high level qualifier.
Question- ASCII to EDBCDIC and Viceversa
What are the standard functions used for this purpose? I'm doing some hand translations to do it but I'd rather use the service, and it's not clear to me how to find it from the C370 Programming Guide. Thanks for any help!!!
Answer
Use the standard iconv() function to convert from one codepage to another.
Question- Migrating from C/370 2.1 to Language Environment/370
I've got a C/370 program that calls a couple of PL/1 routines. It worked fine under C/370 2.1. Now I'm trying to see if it will work with LE/370 C, so I recompiled and relinked it. I needed to specify the PL/1 linktime libraries because of the included PL/1 code, even though there's no support for a common C and PL/1 environment - but I figured that it should work anyway.
Anyhow, any attempt to run the program fails because it can't find module CEEEV010. I use the LE/370 C runtime library when I run it.
What do I need to do?
Answer
The entire application needs to be linked with LE, and nothing else. eg. DO NOT include the old PL/I stubs, or the common library stubs, just use SCEELKED (from LE) and you should be okay.
CEEEV010 is part of LE/370 - one of the PL/I parts.
Question- Using TCP/IP #includes
I have a C program that has an #include for a member from the TCP/IP PDS (we have TCP/IP 2.2.1). These #include members have numbers in columns 73-80 which isn't very nice. All our other #include libraries are VB files that could have data well beyond column 72. The end result is that the compiler does not like the numbers in those columns.
Short of editing the TCP/IP and removing data from all those columns , do I have any options?
Answer
Any include file (be it source or header) should have a '#pragma sequence(m,n)' if it has sequence numbers, or '#pragma nosequence' if it doesn't have them.
The pragma is only valid for the current file (base compile or include file) and does not propagate to other files. The compile option applies to all files, unless specifically overridden in a specific file.
If your own code had said '#pragma nosequence' in all files, and you compiled with SEQ(73,80), then it would work, but that is changing everything backwards. All you can do is edit the TCP headers. Best bet is to insert the '#pragma sequence(73,80)' at the top and not touch the data lines below.
Question- C/370 CICS and HEAP Storage
I am about to put a C/370 CICS application in production, however I have discovered a major performance problem. The application does an enormous number of CICS Getmain/Freemains for HEAP/Stack storage, and apparently the HEAP parameter is ignored in a CICS environment. Do you know if the HEAP parameter is supported if I move to LE/370 Runtime?
Answer
HEAP is honoured under LE/370, but not under the non-LE base (C/370 V2).
HEAP is used for static storage + malloc/calloc/realloc. STACK is used for everything else (including automatic storage). As we issue some *alloc routines from within the library, some of these calls are beyond programmer control. If the source of the problem is truly the HEAP allocations, (see REPORT option), the programmer can investigate their own use of the *alloc routines and attempt to combine storage requests (eg. do some of the storage management themselves). If the source of the problem is STACK, some adjustment of the STACK option may be required. Additionally, the EDSA parm at CICS startup may need to be adjusted.
Question- C and LE Support for String Instructions
As you know, some 390 mainframes have support for the string assembler instructions (move string, search string) and others don't. Do the C and LE runtime libraries "know" about these instructions and use them if they are present? If not, is there some way to implement them (without us writing our own functions)? We could really use any performance boost they may offer.
We are using AD/Cycle C/370 V1R2 and LE/370 V1R3. MVS/ESA is 4.3.
Answer
Logical String Assist (LSA) is available via the compiler options:
HWOPTS(STRING) to enable the lsa opcodes HWOPTS(NOSTRING) to disable
Default is NOHWOPTS. STRING is a suboption in case other hardware options come up in the future.
Question- Replicating Initializers
I want to declare an array of structures with initial values, and I was wondering whether there is any way of indicating a "repetition factor", to avoid repeated coding of the initial values. Other languages have this, but I could not find any mention of it in the C manual. This is a simplified example of what I would like to do:
typedef struct { long NumEntries; long NumDone; } HEADER; #define HEADER_DEFAULT 0,0 typedef struct { char Name[8]; long Index; } ENTRY; #define ENTRY_DEFAULT {""},0 /* static structure with 100 entries */ #define MAX_SIZE 100 struct { HEADER Header; ENTRY Entries MAX_SIZE ; } Table={ {HEADER_DEFAULT}, { (MAX_SIZE) {ENTRY_DEFAULT}} };
Here I have used MAX_SIZE as a repetition factor (based on what is valid in other languages), but that is not valid C. Is there a way to do what I want?
Answer
There is no way to indicate a repetition under C unless you want to initialize to 0. If you had a global array:
int x[10000];that you wanted to initialize to 0's, then you could write:
int x[10000] = {0};the compiler will generate code to ensure that the last 9999 full words are initialized to 0. If you wanted to initialize the array to anything else, you're stuck. What is typically done in C is that you would initialize the variable early in your main() program using the memset() function, e.g.
main() { memset(x, 98, sizeof(x)); . . . return(0); }
There is another approach - I don't recommend it though because it might have other affects, but you could use the LE/370 STORAGE runtime option, which will initialize all your storage to a particular value when it is allocated (you can choose different values for HEAP and STACK storage). This will cause your code to crawl and is really intended for debugging purposes.
Question- @@DC370$
What is the @@DC370$ member used for? Does the Prelinker or the Linker use it?
Answer
The @@DC370$ member is created and maintained by the C370LIB utility. The information in this member is used by the prelinker to do AUTOCALL with this library - it contains information about where external variables reside in an object library. If you don't use the PDS for autocall, you don't need this member. To update the member, use the C370LIB utility with the DIR option - to see what's in your library, use the MAP option.
The linker has no understanding of the @@DC370$ member - AUTOCALL libraries that are used for prelinking cannot be used by the linker, since the linker doesn't understand the internal format of the object library.
Question- OS Linkage and variable number of arguments
We have an existing program which accepts variable length parameter lists using "standard" assembler conventions. We are writing C code to invoke that program. The C/370 User's Guide and the C/370 Programming Guide are not clear in their description of "#pragma linkage(routine,OS)".
How do we specify a variable length parameter string in the prototype? Do we say "int routine {...};" ? Does linkage OS set the high order bit to '1'b in the last argument? Do we have to use the va_ functions in stdarg.h?
We can't change the existing program to use EDCPRLG and EDCEPIL. Does linkage OS use "standard" assembler program save area linkage?
My existing program returns values to locations specified as parameters. Do we pass the addresses, or does linkage OS build this for us? In other words, do we say "routine(&arg1,&arg2,&arg3,&rc,&reas);" or do we say "routine(arg1,arg2,arg3,rc,reas);"?
Answer
If you want to call a function with OS linkage, you can code the following:
int FN(int x, int y, int z); #pragma linkage(FN, OS)
When you call the function, the last parameter will have the high order bit set on to indicate it is the last parameter. We use standard save area linkage, I believe, so you should be ok.
You can actually pass variables by reference or by value for OS linkage - they both amount to the same thing. We recommend that you pass variables by address; we find it makes things simpler. If you pass variables by value, the compiler will create a temporary variable to copy the variable into, then take the address of that, so you'll be getting worse code if you pass variables by address. For example, if you have an OS linkage function that will be getting an integer by reference, you could code either:
int FN(int x); #pragma linkage(FN, OS) . . . int x = 7; y = FN(x);or you could code:
int FN(int* x); #pragma linkage(FN, OS) . . . int x = 7; y = FN(&x);both would work, but the first style would cause the compiler to (in essence) generate:
int x = 7; int* temp = &x; y = FN(temp);to maintain call-by-value semantics.
Question- Problems using fldata
I'm having a problem using fldata. I execute the following program, passing the argument 'SYS1.CLIST'.
#include <stdio.h> fldata_t filedata; FILE *infile; int i; main(int argc, char *arg&lrbk.]) { for (i=2; i<argc; i++) *(arg[i]-1) = ' '; infile = fopen(arg[i],"r"); if (!infile) exit(1); fldata(infile, NULL, &filedata); printf("FILEDATA.__DSNAME = <%s>\n",filedata.__dsname); printf("FILEDATA.__RECFMF = <%i>\n",filedata.__recfmF); printf("FILEDATA.__RECFMV = <%i>\n",filedata.__recfmV); printf("FILEDATA.__RECFMBlk = <%i>\n",filedata.__recfmBlk); printf("FILEDATA.__DSORGPO = <%i>\n",filedata.__dsorgPO); printf("FILEDATA.__DSORGPS = <%i>\n",filedata.__dsorgPS); printf("FILEDATA.__MAXRECLEN = <%i>\n",filedata.__maxreclen); printf("FILEDATA.__BLKSIZE = <%i>\n",filedata.__blksize); fclose(finfile); }
And I get the following results
FILEDATA.__DSNAME = <SYS1.CLIST> FILEDATA.__RECFMF = <0> FILEDATA.__RECFMV = <0> Should be 1 (Variable Records) FILEDATA.__RECFMBlk = <0> Should be 1 (Blocked) FILEDATA.__DSORGPO = <1> FILEDATA.__DSORGPS = <0> FILEDATA.__MAXRECLEN = <256> Should be 255 FILEDATA.__BLKSIZE = <256> Should be 3665
Answer
These results are correct. When using fldata with a Partitioned Data Set name with no member specified, fldata returns the values specified for the directory of the PDS which does not have variable blocked records, but has a record length of 256 and a blocksize of 256.
Question- Compilation Problem
I'm having a problem using stat.h on CMS. When I compile the following program I get the message that "The operation cannot be performed on an incomplete struct or union". It works with other other C Compilers. Why doesn't this program compile under CMS?
#include <stdio.h> #include <stat.h> main(int argc, char *arg&lrbk.]) { printf("SIZE OF STRUCT is%i>\n",sizeof(struct stat)); }
Answer
The stat.h is not part of the ANSI standard. The compiler gives you the message because there is a stat.h file with the compiler for use by MVS OpenEdition applications. However, the preprocessor on VM makes the struct stat incomplete, hence no operation can be preformed.
If you did not get a copy of any of our previous editions, just let us know and we will be more than happy to send them to you.
If you haven't already sent for your free subscription to this newsletter, now is the time to mail it in. So far, we have almost been able to keep to our plan of four issues a year. If you prefer, mail or fax your business card to the address/phone number on the Reader's Comment Form. You can also subscribe to this newsletter via INTERNET. Just send a message containing your name, full mailing address and phone number, in case we have to talk to you to inetc370 @ vnet.ibm.com or IBMMAIL(CAIBMRXZ).
For the many of you sending in the reply forms with your comments, please include your phone number as we may need to call you to discuss your comments further. Please keep your cards, letters, faxes and messages coming so we can continue to provide this service and improve the newsletter. We really thank the many of you who have already sent your comments and subscriptions in.
In future issues, we'll have some performance tips and answer some more of your questions. Thanks for reading; please let us know what you think of this newsletter.
+-------------------------------------------------------------------+This newsletter was produced by the IBM Software Solutions Toronto Laboratory. For further information on any of the products mentioned, please contact your local IBM office, or an authorized IBM Business Partner.
Numerous product references in this publication are registered trademarks or trademarks of International Business Machines Corporation, unless otherwise indicated. IBM Canada Ltd., a related company is a licensee.
This newsletter was created and marked for processing using IBM BookMaster ® (Program Number 5688-015) and IBM Document Composition Facility (DCF)(Program Number 5748-XX9). The final copy was printed on an IBM 3825 Page Printer, an Advanced Function Printer.
This newsletter is © Copyright IBM Corporation 1995. In Canada - © Copyright IBM Canada Ltd. 1995. +---------------------------------------------------------------------+
____________________________________________________________________
____________________________________________________________________
____________________________________________________________________
____________________________________________________________________
____________________________________________________________________
____________________________________________________________________
____________________________________________________________________
____________________________________________________________________
____________________________________________________________________
____________________________________________________________________
Please note:
____________________________________________________________________
Thank you for your cooperation and help. You can either mail this form to us, hand it into an IBM office for forwarding or send a message containing your full mailing address and phone number to IBMMAIL(CAIBMRXZ) or inetc370 @ vnet.ibm.com.
You can also fax the form to us. Our fax number is 416-448-6057. Please mark your fax for the attention of Gord Sinclair. Thanks.
Gordon Sinclair Software Solutions Toronto Laboratory IBM Canada Ltd 23/604/844/TOR 844 Don Mills Road North York Ontario, Canada M3C 1V7
( ) Products marked (TM) or ® are trademarks or registered trademarks of the International Business Machines Corporation, unless otherwise indicated. Company, product or service marked ** may be a trademark or service mark of others.