[an error occurred while processing this directive]

HP OpenVMS Systems

C Programming Language
Content starts here

Compaq C
Migration Guide for OpenVMS VAX Systems


Previous Contents

1.3.3 Compaq C RTL Obsolete Features

This section lists features that are considered obsolete in the Compaq C RTL; they are retained for VAX C RTL compatibility only and should not be used for any new development.

1.3.3.1 VAXC$MALLOC_OPT and Related Routines

The following routines are considered obsolete in the Compaq C RTL. The Compaq C RTL versions of the standard C memory allocation routines are faster and more efficient than the VAX C RTL versions.

  • VAXC$CALLOC_OPT
  • VAXC$CFREE_OPT
  • VAXC$FREE_OPT
  • VAXC$MALLOC_OPT
  • VAXC$REALLOC_OPT

1.3.3.2 sys_nerr and sys_nerrlist Global Symbols

The global symbols sys_nerr and sys_errlist are obsolete in the Compaq C RTL. They are provided for VAX C RTL compatibility only; new error messages have not been added for a number of releases of the VAX C RTL. The symbols are still provided in the <perror.h> header file. Programmers are advised to use the portable ANSI C functions perror or strerror instead.

1.3.4 Debugging and the Compaq C RTL Object Library

The Compaq C RTL object library contains a LIB$INITIALIZE psect contribution. When debugging programs linked against the Compaq C RTL versions of the object libraries, you must enter GO to reach the main program, and error tracebacks will have an additional call stack listed. For example:


$ CC/DECC/DEBUG/NOOPTIMIZE HELLOWORLD
$ LINK/DEBUG HELLOWORLD,SYS$LIBRARY:DECCRTL/LIBRARY
$ RUN HELLOWORLD

         VAX DEBUG Version V6.0DS-004

%DEBUG-I-INITIAL, language is C, module set to HELLOWORLD
%DEBUG-I-NOTATMAIN, type GO to get to start of main program

DBG> GO
break at routine HELLOWORLD\main
   425: main()
DBG> GO
Hello world!
%DEBUG-I-EXITSTATUS, is '%SYSTEM-S-NORMAL, normal successful completion'
DBG> EXIT
$

1.4 C RTL Interoperability Concerns

This section documents interoperability restrictions that apply when multiple copies of the C RTL are used in the same process (or in spawned processes) as part of running an application.

Most applications are expected to work correctly with any mix of C RTLs in the same process. However, any shareable image that exchanges part of the C RTL context with its caller could lead to problems in an image that uses two or more C RTLs (see Section 1.4.1). Also, there can be link conflicts when building an application that uses multiple C RTLs (see Section 1.4.2). Finally, you must be sure to avoid version mismatches of RTL components when distributing certain Compaq or user-written applications to other systems (see Section 1.4.3).

The following are examples of mixed C RTL use:

  • A single program is composed of modules created by both VAX C and Compaq C (or Compaq C++) and is linked in the default manner so that the VAX C modules call VAXCRTL.EXE and the Compaq C modules call DECC$SHR.EXE:
  • A program is linked with DECC$SHR.EXE (because it was created with Compaq C or Compaq C++ or it was linked using DECCRTL.OLB), and also calls some shareable image that is linked with VAXCRTL.EXE, such as DECwindows, CDD, and so forth:
  • A program calls two different shareable images. One shareable image links with VAXCRTL.EXE and the other links with DECC$SHR.EXE:
  • A program is linked with VAXCRTL.OLB and also calls some shareable image that is linked with VAXCRTL.OLB or DECCRTL.OLB:
  • A program calls two different shareable images. Each shareable image was linked with DECCRTL.OLB:

1.4.1 Problems with Images that Export C RTL Context

Most applications are expected to work correctly with any mix of C RTLs in the same process. However, any shareable image that exchanges part of the C RTL context with its caller could lead to problems in an image that uses two C RTLs. Furthermore, these problems can occur in an indeterminate way.

The term C RTL context refers to the program state information that is maintained by the C RTL to implement C language semantics. Generally, this is information that applies to the program as a whole, not to one specific subroutine. An example of C RTL context is the file descriptor table. File descriptors are a C language concept maintained by the C RTL. Application variables and the process priority are examples of what is not part of C RTL context. The first is part of the application context. The second is part of the OpenVMS context.

A program that exports C RTL context is said to be unencapsulated; one that does not export C RTL context is said to be encapsulated.

An exporter of C RTL context is likely to be a programming library, but any program consisting of multiple shareable images might also pass C RTL context between images.

Exporting C RTL context between two instances of C RTLs generally will not work. A shareable image that needs to pass C RTL context to its caller must ensure that the caller will be built with the same copy of a C RTL as the shareable image. C RTL context can never be passed between a C RTL object library and a C RTL shareable image, even if they are instances of the same C RTL.

The following is a complete list of the data structures and information that comprise the C RTL context:

  • The free memory list maintained by malloc and free
  • File descriptors and file pointers, including stdin , stdout , and stderr
  • errno
  • Child process context
  • Random number seed
  • Signal context
  • vaxc$crtl_init and main context, including the environ variable

There are some general solutions to these restrictions. The provider of a subsystem has a couple of options:

  • If the subsystem appears as an extension to the C language environment, one solution is to build a different version of the subsystem for each of the C environments.
  • If the subsystem is an application program interface (API) that is independent of C environments, another option is to move usage of the C RTL inside the subsystem API.

For users of an unencapsulated subsystem, one option is to carefully use #define preprocessor macros to map appropriate VAX C RTL routine calls into Compaq C routine calls without mapping all of them (see Section 1.4.1.1).

The following list gives some instances of exporting C RTL context. The term subsystem refers to a shareable image that provides a set of routines to be called by the caller, which is typically a main program, or possibly another shareable image. If any of these instances occur in an application where a subsystem is linked with one C RTL, and the caller of that subsystem is linked with a different C RTL, then the application may not function correctly.

  • A subsystem that allocates memory with calls to malloc and requires its caller to deallocate the memory at a later time by calling free directly. Memory leakage will occur as a result of such an operation.
  • A subsystem that opens a file and returns a file pointer for its callers to use by calling fprintf directly.
  • A subsystem that reads a line from stdin and expects its caller to access the read data with calls to getc .
  • A subsystem that expects its caller to provide a readable value in the errno global variable.
  • A subsystem that calls vfork and expects its callers to perform a corresponding exec call.
  • Any attempt to exec an image that was built with a different C RTL than the image that performed the exec call. Possible symptoms of such an attempt would include no output produced by the child process, or a program that fails with a "bad file number" message.
  • A subsystem that expects single-character output to the terminal to occur sequentially, in a readable form, when the caller is also performing single-character output to the terminal.

In general, it is a good idea for subsystems to not export C RTL context. If a subsystem used by an application does export C RTL context, the only solution that insures that the application will run correctly is for the subsystem and the caller to use the same copy of that C RTL. For example, if the subsystem is linked with VAXCRTL.EXE, then the caller must also be linked with VAXCRTL.EXE. If the subsystem is linked with DECC$SHR.EXE, then the caller must also be linked with DECC$SHR.EXE. Note that any shareable image that does not export C RTL context will continue to function correctly with whatever version of the C RTL it is currently using.

The following sections describe solutions to the unencapsulated problem.

1.4.1.1 Becoming Encapsulated---Solutions to the General Problem

There are several options available for changing an unencapsulated image into an encapsulated one:

  • The subsystem developer that provides the API definition can change the subsystem.
    The simplest general solution is to move use of the C RTL inside the subsystem API. This has the advantage of permitting the subsystem to be reimplemented without affecting users and permits the subsystem to be used from programming languages other than C. An example where this was done is the X Windows Intrinsics function xtfree . Callers of xtmalloc previously released virtual memory using the C RTL free function. Now users must call xtfree .
  • The application programmer that uses the subsystem can write a jacket around the unencapsulated API.
    Suppose subsystem XYZ provided a routine xyzcreate that returned a pointer to virtual memory, and the application released that virtual memory using free . The application could create a routine free_for_xyz that calls free . By using free_for_xyz with the same C RTL (either Compaq C or VAX C) used by XYZ, the application can encapsulate subsystem XYZ. This method is shown in the following example:


    $ create my_api_memory.c
    void free_for_XYZ (void *p)
    {
      free (p);
      return;
    }
    $ CC/VAXC my_api_memory.c
    $ LINK/MAP/FULL/CROSS myapp, my_api_memory, SYS$INPUT/OPT
    SYS$SHARE:VAXCRTL/SHARE
    

    Note that the jacket routine my_api_memory.c is compiled with VAX C and linked as for a mixed Compaq C/VAX C application.
    There are many variations on this theme. Consider a subsystem XYZ that uses Compaq C and an application that uses VAX C. The application can use mostly VAX C code, but use #define preprocessor macros to change VAX C RTL function calls that would otherwise export C RTL context to function calls to the Compaq C RTL. Since all Compaq C RTL routine names begin with the DECC$ prefix, a sample #define macro might look like this:


    #define free_for_XYZ decc$free
    

1.4.1.2 Issues for File I/O

If a subsystem returns C file descriptors or file pointers, the application and subsystem must both use the same C RTL. You can use the previous general techniques to encapsulate an unencapsulated subsystem.

For the case of stdin , stdout , and stderr , each instance of the C RTL has its own channel open to these files. The resulting behavior is line-at-a-time processing of input or output. This is much the same as if the application mixed C standard I/O with the standard input or output channels of a different programming language.

1.4.1.3 Considerations for errno

The Compaq C RTL is dependent on a new image, SYS$LIBRARY:CMA$TIS_SHR.EXE, to provide errno support. If you implement a run-time library that modifies errno to communicate error status to callers, do not modify errno directly. If you do, the modified errno will not be communicated to all C RTLs in the process. For example, if a shareable image that modifies errno is linked with the Compaq C RTL, and the main program is linked with the VAX C RTL, the main program will never see the modified errno value from the shareable image.

The recommended way to modify errno is to call the function cma$tis_set_errno_value . This function has the following prototype:


void cma$tis_errno_set_value(int value);

For example, consider an image that needs to modify errno and has code similar to the following:


if (error_situation)
    {
    errno=ERROR_CODE;
    return(error_status);
    }

To correctly modify errno , change this code to the following:


if (error_situation)
    {
    void cma$tis_errno_set_value(int);
    cma$tis_errno_set_value(ERROR_CODE);
    return(error_status);
    }

Note that programs that merely examine the value of errno are not affected by this implementation change.

1.4.1.4 Child Process Context

When spawning a child process using vfork , the main routine in the child uses a C RTL routine to inherit some context from the parent. This context is documented in the Compaq C RTL Reference Manual for OpenVMS Systems, and includes the list of open file descriptors, among other things. The restrictions on mixed C RTL context between different instances of the C RTL applies here as well.

Because of changes in the implementation of forking, both the parent and child process must use the same C RTL to communicate the C RTL context, as shown in the following figure:


The C RTL context passed from the parent is limited to the context visible from the exec routine called. Therefore, if the Compaq C RTL exec routine is called, only files opened in the Compaq C RTL are passed to the child process.

In the child process, the C RTL routine called by main re-establishes the context that gets used. Therefore, if main is using the Compaq C RTL, the inherited file descriptors are reopened by the Compaq C RTL. These file descriptors are not visible to the VAX C RTL.

A related problem is context between vfork and exec . The vfork routine establishes some context that gets used by the exec routines. While this context is implicitly passed (rather than explicitly by the application), it has the same restriction as other mixed C RTL context. The version of vfork must match the version of exec (that is, a Compaq C RTL version of vfork must match the Compaq C RTL version of exec ).

1.4.1.5 Random Number Seed

Each C RTL linked into the application will have its own random number seed. The effect is that each C RTL will have the exact same pseudo-random sequence. If the application intends to call srand to set the random number seed, each seed must be updated.

1.4.1.6 Signal Context

The C RTL internally maintains some context to describe signal handlers that have been enabled. With multiple instances of the C RTL in one process, there can be multiple signal handlers enabled for the same signal. For software signals, the signal handler used is the one that matches the section of the application that raises the signal. For signals caused by hardware exceptions (such as reserved operand faults, or access violations), the signal handler used depends on active call frames. Calls to setjmp establish a C RTL condition handler for the frame. The main program always has a C RTL condition handler enabled. The most recent frame that has a C RTL condition handler established will catch the hardware exception. If this C RTL condition handler is for Compaq C, it looks for a signal handler established with a Compaq C RTL signal or sigvec routine. If the condition handler is for VAX C, then the signal handler established with the VAX C RTL gets invoked.

1.4.1.7 VAXC$CRTL_INIT and Context Initialization for main Program

As mentioned previously, some C RTL context initialization occurs when the main program starts and whenever the vaxc$crtl_init routine is called. This initialization includes establishing a VAX condition handler to handle hardware exceptions, inheriting context from the parent process if this is a child process, establishing a Ctrl/C handler, setting the default umask , and setting up environment variables accessible through the global object environ .

When multiple C RTLs are used in one application, only one set of context is initialized by default. To get the other C RTL context initialized, you must make an explicit call to the other version of vaxc$crtl_init . If, for example, a main program that is linked with the VAX C RTL calls a subroutine that is linked with the Compaq C RTL, the subroutine must contain an explicit call to vaxc$crtl_init to initialize the correct RTL context (Compaq C RTL, in this case) for later access.


Previous Next Contents