Compaq C
Compaq C User's Guide for OpenVMS Systems
1.4.7 Linker Error Messages
If the linker detects any errors while linking object modules, it
displays messages indicating the cause and severity of the error. If
any error or fatal error conditions occur (that is, errors with
severities of E or F), the linker does not produce an image file.
The messages produced by the linker are descriptive, and you do not
usually need additional information to determine the specific error.
Some common errors that occur during linking are as follows:
- An object module has compilation errors.
This occurs when you
try to link a module that produced warning messages during compilation.
You can usually link compiled modules for which the compiler generated
messages, but verify that the modules will produce the output you
expect.
- The input file has a file type other than OBJ and no file type was
specified on the command line.
If you do not specify a file type,
the linker searches for a file that has a file type of OBJ by default.
If the file is not an object file and you do not identify it with the
appropriate file type, the linker signals an error message and does not
produce an image file.
- You tried to link a nonexistent module.
The linker signals an
error message if you misspell a module name on the command line or if
the compilation contains fatal diagnostics.
- A reference to a symbol name remains unresolved.
An error
occurs when you omit required module or library names from the command
line and the linker cannot locate the definition for a specified global
symbol reference. Consider, for example, the following LINK command for
a main program module, OCEAN.OBJ, that calls the subprogram modules
REEF.OBJ, SHELLS.OBJ, and SEAWEED.OBJ:
$ LINK OCEAN, REEF, SHELLS
|
Because SEAWEED is not linked, the linker issues the following
error messages:
%LINK-W-NUDFSYMS, 1 undefined symbol
%LINK-I-UDFSYMS, SEAWEED
%LINK-W-USEUNDEF, module "OCEAN" references undefined symbol "SEAWEED"
%LINK-W-DIAGISUED, completed but with diagnostics
|
If an error occurs when you link modules, you can often correct it by
reentering the command and specifying the correct modules or libraries.
If an error indicates that a program module cannot be located, you may
be linking the program with the wrong RTL.
For a complete list of linker messages, see the OpenVMS System Messages and Recovery Procedures Reference Manual.
1.5 Running a Compaq C Program
After you link your program, you can use the DCL command RUN to execute
it. The RUN command has the following format:
RUN [/[NO]DEBUG] file-spec [/[NO]DEBUG]
|
/[NO]DEBUG
An optional qualifier. Specify the /DEBUG qualifier to invoke the
debugger if the image was not linked with it. You cannot use /DEBUG on
images linked with the /NOTRACEBACK qualifier.
If the image was linked with the /DEBUG qualifier and you do not want
the debugger to prompt you, use the /NODEBUG qualifier. The default
action depends on whether the file was linked with the /DEBUG qualifier.
file-spec
The file you want to run.
The execution of a program begins at the function whose identifier is
main
, or, if there is no function with this identifier, at the first
function seen by the VMS linker.
Note
Unexpected results might occur if you don't have a function called
main
.
|
The following example executes the image SAMPLE.EXE without invoking
the debugger:
For more information on debugging programs, see Section C.1.
During execution, an image can generate a fatal error called an
exception condition. When an exception condition occurs, the
system displays an error message. Run-time errors can also be issued by
the operating system or by utilities.
When an error occurs during the execution of a program, the program is
terminated and the OpenVMS condition handler displays one or
more messages on the currently defined SYS$ERROR device.
A message is followed by a traceback. For each module in the image that
has traceback information, the condition handler lists the modules that
were active when the error occurred, which shows the sequence in which
the modules were called.
For example, if an integer divide-by-zero condition occurs, a run-time
message like the following appears:
%SYSTEM-F-INTDIV, arithmetic trap, integer divide by zero
at PC=00000FC3, PSL=03C00002
|
This message is followed by a traceback message similar to the
following:
%TRACE-F-TRACEBACK, symbolic stack dump follows
module name routine name line rel PC abs PC
A C 8 00000007 00000FC3
B main 1408 000002F7 00000B17
|
The information in the traceback message follows:
module name
The name or names of an image module that was active when the error
occurred.
The first module name is that of the module in which the error
occurred. Each subsequent line gives the name of the caller of the
module named on the previous line. In this example, the modules are A
and B; main called C.
routine name
The name of the function in the calling sequence.
line
The compiler-generated line number of the statement in the source
program where the error occurred, or at which the call or reference to
the next procedure was made. Line numbers in these messages match those
in the listing file (not the source file).
rel PC
The value of the PC (program counter). This value represents the
location in the program image at which the error occurred or at which a
procedure was called. The location is relative to the virtual memory
address that the linker assigned to the code program section of the
module indicated by module name.
abs PC
The value of the PC in absolute terms; that is, the actual address in
virtual memory representing the location at which the error occurred.
Traceback information is available at run time only for modules
compiled and linked with the traceback option in effect. The traceback
option is in effect by default for both the CC and LINK commands. You
may use the CC command qualifier /NODEBUG and the LINK command
qualifier /NOTRACEBACK to exclude
traceback information. However, traceback information should be
excluded only from thoroughly debugged program modules.
1.6 Passing Arguments to the main Function
The
main
function in a Compaq 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[ ])
{...}
|
argc
The number of arguments in the command line that invoked the program.
argv
A pointer to an array of character strings that contain the arguments.
envp
The environment array. It contains process information such as the user
name and controlling terminal. It has no bearing on passing
command-line arguments. Its primary use in Compaq C programs is
during
exec
and
getenv
function calls. (For more information, see the Compaq C Run-Time Library Reference Manual for OpenVMS Systems).
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.
Example 1-1 Echo Program Using Command-Line
Arguments |
/* 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.
Compaq C internally parses and modifies the altered command line
to make Compaq 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.
1.7 64-bit Addressing Support (ALPHA ONLY)
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:
- Typical C usage involves many objects accessed through pointers
rather than single monolithic arrays or structures.
- Huge declared objects would have an impact on object-module format
and the linker.
Note
Single objects larger than 2 gigabytes are not fully supported, even
with 64-bit virtual addressing in effect.
|
- Minimal source-code edits are required to exploit the 64-bit space
where needed. Because the pragmas affect a region of source code, it is
not necessary to modify every declaration.
No changes are required for existing 32-bit applications that do not
need to exploit 64-bit addressing.
1.7.1 Qualifiers and Pragmas
The following qualifiers, pragmas, and predefined macro control pointer
size:
- /[NO]POINTER_SIZE={LONG | SHORT | 64 |32}
- /[NO]CHECK=[NO]POINTER_SIZE=(option,...)
-
#pragma pointer_size
-
#pragma required_pointer_size
-
__INITIAL_POINTER_SIZE
predefined macro
1.7.1.1 The /POINTER_SIZE Qualifier
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:
- Disables pointer-size features, such as the ability to use
#pragma pointer_size
- Directs the compiler to assume that all pointers are 32-bit
pointers.
This default represents no change over previous versions of
Compaq C.
Specifying /POINTER_SIZE with a keyword value (32, 64, SHORT, or LONG)
has the following effects:
- Enables processing of
#pragma pointer_size
.
- Sets the initial default pointer size to 32 or 64, as specified.
- Predefines the preprocessor macro
__INITIAL_POINTER_SIZE
to 32 or 64, as specified. If /POINTER_SIZE is omitted from the command
line,
__INITIAL_POINTER_SIZE
is 0, which allows you to use
#ifdef __INITIAL_POINTER_SIZE
to test whether or not the compiler supports 64-bit pointers.
- For /POINTER_SIZE=64, the Compaq C RTL name mapping table is
changed to select the 64-bit versions of
malloc
,
calloc
, and other RTL routines by default.
Use of the /POINTER_SIZE qualifier also influences the processing of
Compaq C RTL header files:
- For those functions that have both 32-bit and 64-bit
implementations, specifying /POINTER_SIZE enables function prototypes
to access both functions, regardless of the actual value supplied to
the qualifier. The value specified to the qualifier determines the
default implementation to call during that compilation unit.
- Functions that require a second interface to be used with 64-bit
pointers reside in the same object libraries and shareable images as
their 32-bit counterparts. Because no new object libraries or shareable
images are introduced, using 64-bit pointers does not require changes
to your link command or link options files.
See the Compaq C Run-Time Library Reference Manual for OpenVMS Systems for more information on the impact of 64-bit
pointer support on Compaq C RTL functions.
See Section 1.3.4 for more information about /POINTER_SIZE.
1.7.1.2 The __INITIAL_POINTER_SIZE Macro
The
__INITIAL_POINTER_SIZE
preprocessor macro is useful for header-file authors to determine:
- If the compiler supports 64-bit pointers.
- If the application expects to use 64-bit pointers.
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. */
|
1.7.1.3 The /CHECK=POINTER_SIZE Qualifier
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.
1.7.1.4 Pragmas
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 intended for use 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.18 and 5.4.19 for more information on
the pointer-size pragmas.
1.7.2 Determining Pointer Size
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:
- The * in a declaration or cast:
int **p; // Declaration
ip = (int **)i; // Cast
|
- The outer (leftmost) brackets [] in a formal parameter imply a *:
void foo(int ia[10][20]) {}
// Means the following:
void foo(int (*ia)[20]) {}
|
- A function declarator as a formal parameter imply a *:
void foo (int func()):
// Means the following:
void foo (int (*)() func);
|
- Any formal parameter of array or function type implies a *, even
when bound in a
typedef
:
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.
|
1.7.2.1 Special Cases
The following special cases are not affected by pointer-size context:
- Formal parameters to
main
are always treated as if they were in a
#pragma pointer_size system_default
context, which is 32-bit pointers for OpenVMS systems.
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); }
|
- A string literal produces a 32-bit pointer when used as an rvalue:
#pragma pointer_size 64
ASSERT(sizeof("x" + 0) == 4);
|
- The
&
operator yields a 32-bit pointer unless it is applied to pointer
dereference, in which case it is the size of the dereferenced pointer
type:
sizeof(&foo) == 32
sizeof(&s ->next) == sizeof(s)
|
- An rvalue cast to a 32-bit pointer type does not modify the
high-order 32 bits of a 64-bit operand.
sizeof
yields 4 bytes, but the high bits are not lost unless a 4-byte
assignment occurs:
#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
|
|
|