United States    
COMPAQ STORE | PRODUCTS |
SERVICES | SUPPORT | CONTACT US | SEARCH
Compaq C

Compaq C
User's Guide for OpenVMS Systems


Previous Contents Index

1.7.2.2 Mixing Pointer Sizes

An application can use both 32-bit and 64-bit addresses. The following semantics apply when mixing pointers:

1.7.3 Header File Considerations

The following general header-file considerations should be kept in mind:

Be aware that pointer-size controls are not unique in the way they affect header files; other features that affect data layout have similar impact. For example, most header files should be compiled with 32-bit pointers regardless of pointer-size context. Also, most system header files (on Alpha systems) must be compiled with member_alignment regardless of user pragmas or qualifiers.

To address this issue more generally, the pragma environment directive can be used to save context and set header defaults at the beginning of each header file, and then to restore context at the end. See Section 5.4.4 for a description of pragma environment .

For header files that have not yet been upgraded to use #pragma environment, the /POINTER_SIZE=64 qualifier can be difficult to use effectively. For such header files that are not 64-bit aware, the compiler automatically applies user-defined prologue and epilogue files before and after the text of the included header file. See Section 1.7.4 for more information on prologue/epilogue files.

1.7.4 Prologue/Epilogue Files

Compaq C automatically processes user-supplied prologue and epilogue header files. This feature is an aid to using header files that are not 64-bit aware within an application that is built to exploit 64-bit addressing.

1.7.4.1 Rationale

Compaq C header files typically contain a section at the top that:

  1. Saves the current state of the member_alignment , extern_model , extern_prefix , and message pragmas.
  2. Sets these pragmas to the default values for the system.

A section at the end of the header file then restores these pragmas to their previously-saved state.

Mixed pointer sizes introduce another kind of state that typically needs to be saved, set, and restored in header files that define fixed 32-bit interfaces to libraries and data structures.

The #pragma environment preprocessor directive allows headers to control all compiler states (message suppression, extern_model , member_alignment , and pointer_size ) with one directive.

However, for header files that have not yet been upgraded to use #pragma environment , the /POINTER_SIZE=64 qualifier can be difficult to use effectively. In this case, the automatic mechanism to include prologue/epilogue files allows you to protect all of the header files within a single directory (or modules within a single text library). You do this by copying two short files into each directory or library that needs it, without having to edit each header file or library module separately.

In time, you should modify header files to either exploit 64-bit addressing (like the Compaq C RTL), or to protect themselves with #pragma environment . Prologue/epilogue processing can ease this transition.

1.7.4.2 Using Prologue/Epilogue Files

Prologue/epilogue file are processed in the following way:

  1. When the compiler encounters an #include preprocessing directive, it determines the location of the file or text library module to be included. It then checks to see if one or both of the two following specially named files or modules exist in the same location as the included file:


    __DECC_INCLUDE_PROLOGUE.H 
    __DECC_INCLUDE_EPILOGUE.H  
    

    The location is the OpenVMS directory containing the included file or the text library file containing the included module. (In the case of a text library, the .h is stripped off.)
    The directory is the result of using the $PARSE/$SEARCH system services with concealed device name logicals translated. Therefore, if an included file is found through a concealed device logical that hides a search list, the check for prologue/epilogue files is still specific to the individual directories making up the search list.

  2. If the prologue and epilogue files do exist in the same location as the included file, then the content of each is read into memory.
  3. The text of the prologue file is processed just before the text of the file specified by the #include .
  4. The text of the epilogue file is processed just after the text of the file specified by the #include.
  5. Subsequent #includes that refer to files from the same location use the saved text from any prologue/epilogue file found there.

The prologue/epilogue files are otherwise treated as if they had been included explicitly: #line directives are generated for them if /PREPROCESS_ONLY output is produced, and they appear as dependencies if /MMS_DEPENDENCY output is produced.

To take advantage of prologue/epilogue processing for included header files, you need to create two files, __decc_include_prologue.h and __decc_include_epilogue.h , in the same directory as the included file.

Suggested content for a prologue file is:


__DECC_INCLUDE_PROLOGUE.H: 
 
#ifdef __PRAGMA_ENVIRONMENT 
#pragma environment save 
#pragma environment header_defaults 
#else 
#error "__DECC_INCLUDE_PROLOGUE.H: This compiler does not support 
pragma environment" 
#endif 

Suggested content for an epilogue file is:


__DECC_INCLUDE_EPILOGUE.H: 
 
#ifdef __PRAGMA_ENVIRONMENT 
#pragma __environment restore 
#else 
#error "__DECC_INCLUDE_EPILOGUE.H: This compiler does not support 
pragma environment" 
#endif 

1.7.5 Avoiding Problems

Consider the following suggestions to avoid problems related to pointer size:

1.7.6 Examples

The following examples illustrate the use and misuse of 64-bit pointers.

Example 1-2 Watch Out for Pointers to Pointers (**)

/* CC/NAME=AS_IS/POINTER_SIZE */ 
 
#include <stdio.h> 
 
#pragma pointer_size 64 
char  *C[2]    = {"AB, "CD"};  /* sizeof(C) = 16            */ 
char **CPTRPTR = C; 
char **CPTR; 
 
#pragma pointer_size 32 
char  *c[2]    = {"ab, "cd"};  /* sizeof(C) = 8             */ 
char **cptrptr = c; 
char **cptr; 
 
int main (void) 
{ 
    CPTR    =  cptr;           /* No problem.               */ 
    cptr    =  CPTR;           /* %CC-W-MAYLOSEDATA         */ 
 
    CPTRPTR = cptrptr;         /* %CC-W-PTRMISMATCH         */ 
    cptrptr = CPTRPTR;         /* MAYLOSEDATA & PTRMISMATCH */ 
    puts(cptrptr[0]);          /* ab                        */ 
    puts(cptrptr[1]);          /* cd                        */ 
    puts(CPTRPTR[0]);          /* Bad address passed.       */ 
    puts(CPTRPTR[1]);          /* Fetch off end of c.       */ 
} 

Compiling Example 1-2 produces:


$ cc example1/name=as_is/pointer_size 
    cptr    =  CPTR;           /* %CC-W-MAYLOSEDATA         */ 
....^ 
%CC-W-MAYLOSEDATA, In this statement, "CPTR" has a larger 
data size than "short pointer to char".  Assignment may 
result in data loss.) 
 
    CPTRPTR = cptrptr;         /* %CC-W-PTRMISMATCH         */ 
....^ 
%CC-W-PTRMISMATCH, In this statement, the referenced type 
of the pointer value "cptrptr" is "short pointer to char", 
which is not compatible with "long pointer to char". 
 
    cptrptr = CPTRPTR;         /* MAYLOSEDATA & PTRMISMATCH */ 
....^ 
%CC-W-MAYLOSEDATA, In this statement, "CPTRPTR" has a 
larger data size than "short pointer to short pointer 
to char".  Assignment may result in data loss.) 
 
    cptrptr = CPTRPTR;         /* MAYLOSEDATA & PTRMISMATCH */ 
....^ 
%CC-W-PTRMISMATCH, In this statement, the referenced type 
of the pointer value "CPTRPTR" is "long pointer to char", 
which is not compatible with "short pointer to char". 

Example 1-3 Trivial 64-Bit Exploitation

#include <stdio.h> 
#include <stdlib.h> 
__int64 limit, count; 
size_t bytes; 
char  *cp, *prevcp; 
 
int main(int argc, char **argv) 
{ 
    sscanf(argv[1], "%d",  &bytes); 
    sscanf(argv[2], "%Ld", &limit); 
    printf("bytes %d, limit %Ld, tot %Ld\n", 
           bytes,     limit, bytes * limit); 
    for (count=0; count < limit; count++)  { 
        if (!(cp = malloc(bytes)))  { 
           printf(("Max %Ld bytes.\n", bytes * (count + 1)); 
           break; 
    } else if (!prevcp) { 
        printf("First addr %Lx.\n", cp); 
    } 
    prevcp = cp; 
    printf("Last addr %Lx.\n", prevcp); 
} 

Compiling, linking, and running Example 1-3 produces:


$ cc example2 
$ link example2 
$ example2 65536 1234567890123456 
bytes 65536, limit 1234567890123456, tot 
7121664952292605952 
First addr 226008 
Max 42663936 bytes. 
Last addr 2fc8008. 
$ 
$ cc/pointer_size=64 example2 
$ link example2 
$ example2 65536 1234567890123456 
bytes 65536, limit 1234567890123456, tot 
7121664952292605952 
First addr 1c0010010. 
Max 42532864 bytes. 
Last addr 1c2d8e010. 

Example 1-4 Preceding Example No Longer Trivial

#include <stdio.h> 
#include <stdlib.h> 
__int64 limit, count; 
size_t bytes; 
char  *cp, *prevcp; 
 
static void do_args(char **args) 
{ 
    sscanf(argv[1], "%d",  &bytes); 
    sscanf(argv[2], "%Ld", &limit); 
    printf("bytes %d, limit %Ld, tot %Ld\n", 
           bytes,     limit, bytes * limit); 
} 
 
 
int main(int argc, char **argv) 
{ 
    do_args(argv); 
    for (count=0; count < limit; count++)  { 
        if (!(cp = malloc(bytes)))  { 
           printf(("Max %Ld bytes.\n", bytes * (count + 1)); 
           break; 
    } else if (!prevcp) { 
        printf("First addr %Lx.\n", cp); 
    } 
    prevcp = cp; 
    printf("Last addr %Lx.\n", prevcp); 
} 

Compiling Example 1-4 produces:


$ cc/pointer_size=64 example3 
do_args(argv); 
....^ 
%CC-W-PTRMISMATCH, In this statement, the referenced type 
of the pointer value "argv" is "short pointer to char", 
which is not compatible with "long pointer to char". 


Chapter 2
Using OpenVMS Record Management Services

Compaq C for OpenVMS systems provides a set of run-time library functions and macros to perform I/O. Some of these functions perform in the same manner as I/O functions found on C implementations running on UNIX systems. Other Compaq C functions take full advantage of the functionality of the OpenVMS file-handling system. You can also access the OpenVMS file-handling system from your Compaq C program without using the Compaq C Run-Time Library (RTL) functions. In any case, the system that ultimately accesses files on OpenVMS systems is OpenVMS Record Management Services (RMS).

This chapter introduces you to the following RMS topics:

The file-handling capabilities of Compaq C fall into two distinct categories:

This chapter briefly reviews the basic concepts and facilities of RMS and shows examples of their application in Compaq C programming. Because this is an overview, the chapter does not explain all RMS concepts and features. For language-independent information about RMS, see the following manuals in the OpenVMS documentation set:

2.1 RMS File Organization

RMS supports three types of file organization:

The following sections describe these types of file organization.

The organization of a file determines how a file is stored on the media and, consequently, the possible operations on records. You specify the file's organization when you create the file; it cannot be changed.

However, you can use the File Definition Language Editor (FDL) and the CONVERT utility to define the characteristics of a new file, and then fill the new file with the contents of the old file of a different format. For more information, see the OpenVMS Utility Routines Manual.

2.1.1 Sequential File Organization

Sequential files have consecutive records. There are no empty records separating records that contain data. This organization allows the following operations on the file:

Sequential organization is the only kind permitted for magnetic tape files and other nondisk devices.

2.1.2 Relative File Organization

Relative files have records that occupy numbered, fixed-length cells. The records themselves need not have the same length. Cells can be empty or can contain records so the following operations are permitted:

Relative file organization is possible only on disk devices.

2.1.3 Indexed File Organization

Indexed files have records that contain, in addition to data and carriage-control information, one or more keys. Keys can be character strings, packed decimal numbers, and 16-bit, 32-bit, or 64-bit signed or unsigned integers. Every record has at least one key, the primary key, whose value in each record cannot be changed. Optionally, each record can have one or more alternate keys, whose key values can be changed.

Unlike relative record numbers used in relative files, key values in indexed files are not necessarily unique. When you create a file, you can specify that a particular key have the same value in different records (these keys are called duplicate keys). Keys are defined for the entire file in terms of their position within a record and their length.

In addition to maintaining its records, RMS builds and maintains indexes for each of the defined keys. As records are written to the file, their key values are inserted in order of ascending value in the appropriate indexes. This organization allows the following operations:

Indexed organization is possible only on disk devices.

2.2 Record Access Modes

The record access modes are sequential, direct by key, and direct by record file address. The direct access modes are possible only with files that reside on disks.

Unlike a file's organization, the record access mode is not a permanent attribute of the file. During the processing of a file, you can switch from one access mode to any other permitted for that file organization. For example, indexed files are often processed by locating a record directly by key, and then using that key's index to sequentially read all the indexed records in ascending order of their key values; this method is sometimes called the indexed-sequential access method (ISAM).

2.3 RMS Record Formats

Records in RMS files can have the following formats:


Previous Next Contents Index
  

1.800.AT.COMPAQ

privacy and legal statement