United States |
Previous | Contents | Index |
An application can use both 32-bit and 64-bit addresses. The following semantics apply when mixing pointers:
The following general header-file considerations should be kept in mind:
fprintf(FILE *, const char *, ...); |
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:
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:
__DECC_INCLUDE_PROLOGUE.H __DECC_INCLUDE_EPILOGUE.H |
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 |
Consider the following suggestions to avoid problems related to pointer size:
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". |
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:
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 |
|