The main function in a DEC C program can accept arguments from the command line from which it was invoked. The syntax for a main function is:
int main(int argc, char *argv[ ], char *envp[ ]) { . . . }
In the main function definition, the parameters are optional. However, you can access only the parameters that you define. You can define the main function in any of the following ways:
int main() int main(int argc) int main(int argc, char *argv[ ]) int main(int argc, char *argv[ ], char *envp[ ])
To pass arguments to the main function, you must install the program as a DCL foreign command. When a program is installed and run as a foreign command, the argc parameter is always greater than or equal to 1, and argv[0]always contains the name of the image file.
The procedure for installing a foreign command involves using a DCL assignment statement to assign the name of the image file to a symbol that is later used to invoke the image. For example:
$ ECHO == "$DSK$:COMMARG.EXE"<Return>
The symbol ECHO is installed as a foreign command that invokes the image in COMMARG.EXE. The definition of ECHO must begin with a dollar sign ($) and include a device name, as shown.
For more information about the procedure for installing a foreign command, see the OpenVMS DCL Dictionary.
Example 1-1 shows a program called COMMARG.C, which displays the command-line arguments that were used to invoke it.
/* This program echoes the command-line arguments. */ #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { int i; /* argv[0] is program name */ printf("program: %s\n",argv[0]); for (i = 1; i < argc; i++) printf("argument %d: %s\n", i, argv[i]); exit (EXIT_SUCCESS); }
You can compile and link the program using the following DCL command lines:
$ CC COMMARG<Return> $ LINK COMMARG<Return>
A sample output for Example 1-1 follows:
$ ECHO Long "Day's" "Journey into Night"<Return> program: db7:[oneill.plays]commarg.exe;1 argument 1: long argument 2: Day's argument 3: Journey into Night
DCL converts most arguments on the command line to uppercase letters. DEC C internally parses and modifies the altered command line to make DEC C argument access compatible with C programs developed on other systems. All alphabetic arguments in the command line are delimited by spaces or tabs. Arguments with embedded spaces or tabs must be enclosed in quotation marks (" "). Uppercase characters in arguments are converted to lowercase, but arguments within quotation marks are left unchanged.
OpenVMS Alpha 64-bit virtual addressing support makes the 64-bit virtual address space defined by the Alpha architecture available to the OpenVMS operating system and its users. It also allows per- process virtual addressing for accessing dynamically mapped data beyond traditional 32-bit limits.
This support is provided through command-line qualifiers and pragma preprocessor directives that control the size of the C pointer because:
No changes are required for existing 32-bit applications that do not need to exploit 64-bit addressing.
The following qualifiers, pragmas, and predefined macro control pointer size:
The /POINTER_SIZE qualifier lets you specify a value of 64 or 32 (or LONG or SHORT) as the default pointer size within the compilation unit. You can compile one set of modules using 32-bit pointers and another set using 64-bit pointers. Take care when these two separate groups of modules call each other.
The default is /NOPOINTER_SIZE, which:
This default represents no change over previous versions of DEC C.
Specifying /POINTER_SIZE alone (with no value) directs the compiler to assume that all pointers are 32-bit pointers.
Specifying /POINTER_SIZE either alone or with a keyword value (32, 64, SHORT, or LONG) has the following effects:
Use of the /POINTER_SIZE qualifier also influences the processing of DEC C RTL header files:
See the DEC C Run-Time Library Reference Manual for OpenVMS Systems for more information on the impact of 64-bit pointer support on DEC C RTL functions.
See Section 1.3.4 for more information about /POINTER_SIZE.
The __INITIAL_POINTER_SIZE preprocessor macro is useful for header- file authors to determine:
Header-file code can then be conditionalized using the following preprocessor directives:
#if defined (__INITIAL_POINTER_SIZE) /* Compiler supports 64-bit pointers */ #if __INITIAL_POINTER_SIZE > 0 /* Application uses 64-bit pointers */ #if __INITIAL_POINTER_SIZE == 32 /* Application uses some 64-bit pointers, but default RTL routines are 32-bit.*/ #if __INITIAL_POINTER_SIZE == 64 /* Application uses 64-bit pointers and default RTL routines are 64-bit. */
Use the /CHECK=POINTER_SIZE qualifier to generate code that checks 64-bit pointer values at runtime to make sure they can fit in a 32-bit pointer. If such a value cannot be represented by a 32-bit pointer, the run-time code signals a range error (SS$_RANGEERR).
Be aware that the compiler generates the same kinds of warning messages for pointer-size mismatches whether or not this qualifier is specified. The run-time checks can detect problems that cannot be detected at compile time, and can help determine whether or not certain warnings are safe to suppress.
See Section 1.3.4 for more information about /CHECK=POINTER_SIZE, including defaults and an example.
The #pragma pointer_size and #pragma required_pointer_size preprocessor directives can be used to change the pointer size currently in effect within a compilation unit. You can default pointers to 32-bits and then declare specific pointers within the module as 64-bits. In this case, you also need to specifically call the _malloc64 form of malloc to obtain memory from the 64-bit memory area.
These pragmas have the following format:
#pragma pointer_size keyword #pragma required_pointer_size keyword
The keyword is one of the following:
{short|32} | 32-bit pointer |
{long|64} | 64-bit pointer |
save | Saves the current pointer size |
restore | Restores the current pointer size to its last saved state |
The #pragma pointer_size and #pragma required_pointer_size directives work essentially the same way, except that #pragma required_pointer_size always takes effect regardless of command- line qualifiers, while #pragma pointer_size is only in effect when the /POINTER_SIZE command-line qualifier is used.
The #pragma pointer_size behavior allows a program to be built using 64-bit features as purely as a 32-bit program, just by changing the command-line qualifier.
The #pragma required_pointer_size is most useful in header files where interfaces to system data structures must use a specific pointer size regardless of how the program is compiled.
See Sections 5.4.13 and 5.4.14 for more information on the pointer-size pragmas.
The pointer-size qualifiers and pragmas affect only a limited number of constructs in the C language itself. At places where the syntax creates a pointer type, the pointer-size context determines the size of that type. Pointer-size context is defined by the most recent pragma (or command-line qualifier) affecting pointer size.
Here are examples of places in the syntax where a pointer type is created:
int **p; // Declaration ip = (int **)i; // Cast
void foo(int ia[10][20]) {} // Means the following: void foo(int (*ia)[20]) {}
void foo (int func()): // Means the following: void foo (int (*)() func);
typedef int a_type[10]; void foo (a_type ia); // Means the following: void foo (int *ia);
Note that a typedef binds the meaning of pointer syntax while a macro does not. Even though both constructs can contain a * used in a declaration, the * in the macro definition is not affected by any pointer-size controls until the point at which the macro is expanded. For example:
#pragma pointer_size 64 typedef int * j_ptr; // * is 64-bit #define J_PTR int * // * is not analyzed #pragma pointer_size 32 j_ptr j; // j is a 64-bit pointer. J_PTR J; // J is a 32-bit pointer.
The following special cases are not affected by pointer-size context:
For example, regardless of the #pragma pointer_size 64 directive, argv[0] is a 32-bit pointer:
#pragma pointer_size 64 main(int argc, char **argv) { ASSERT(sizeof(argv[0]) == 4); }
#pragma pointer_size 64 ASSERT(sizeof("x" + 0) == 4);
sizeof(&foo) == 32 sizeof(&s ->next) == sizeof(s)
#pragma pointer_size 64 typedef int * ip64; #pragma pointer_size 32 typedef int * ip32; ip64 a,b; ip32 c; a = (ip32)b; // No high-order bits are lost c = (ip32)b; // High-order bits are lost
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 *, ...);
A "FILE * fp;" in a declaration in a different area of source code might be a different size.
If /POINTER_SIZE is specified alone or with a value, _malloc64 or _malloc32 can be called explicitly. If /POINTER_SIZE is not specified, the program is compiled to be unaware of 64-bit pointers, and so the declarations of these alternate variants are suppressed.
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.3 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.
DEC 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.
DEC 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 DEC C RTL), or to protect themselves with #pragma environment. Prologue/epilogue processing can ease this transition.
Prologue/epilogue file are processed in the following way:
__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.
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.
/* 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".
#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.
#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".