📄 pgqa.gml
字号:
.book &cmpname User's Guide
.do end
for more details.
.np
.ix 'NULL pointer'
.ix 'portability' 'NULL pointer'
Some compilers allow the
.id NULL
pointer to be dereferenced and return
.id NULL
(we have never understood the rationale behind this, nor why some
compilers continue to support this type of code).
Leaving the aesthetics of this type of code behind, using the
.id NULL
dereferencing assumption in a program will ensure that the program
will not be portable.
Source code which contains the
.id NULL
dereferencing assumption must be corrected before it will work with
&cmpname..
.np
.ix 'signed char'
.ix 'portability' 'signed char'
Programs that assume that the "char" type is "signed" should use the
&cmpname compiler "j" option.
The "j" option will indicate to the &cmpname compiler that the "char"
type is "signed" rather than the default "unsigned".
.*
.beglevel
.*
.section Conversion from UNIX compilers
.*
.np
.ix 'converting to &cmpname' 'from UNIX'
.ix 'UNIX'
The ISO/ANSI standard for C (which &cmpname adheres to) is very similar to
UNIX C.
.if '&target' ne 'QNX' .do begin
Most of the effort in converting UNIX C programs will involve
replacing references to library functions (such as the CURSES
library).
There are many third-party libraries which are implementations of UNIX
libraries on IBM-compatible Personal Computers.
.do end
There is a common problem which many older UNIX programs exhibit,
namely, functions that accept a variable number of arguments are coded
in many different ways.
Functions accepting a variable number of arguments must be coded
according to the ISO standard if they are to work with &cmpname..
We will code an example of a function which will return the maximum of
a list of positive integers.
.ix 'example' 'variable number of arguments'
.ix 'variable number of arguments'
.millust begin
/*
variable number of arguments example
*/
#include <stdarg.h>
int MaxList( int how_many, ... )
{
va_list args;
int max;
max = 0;
va_start( args, how_many );
while( how_many > 0 ) {
value = va_arg( args, int );
if( value > max ) {
max = value;
}
}
va_end( args );
return( max );
}
.millust end
.pc
Notice that the standard header file
.fi STDARG.H
must be included in any source file which defines a function that
handles a variable number of arguments.
The function "MaxList" must be prototyped correctly in other source
files external to the source file containing the definition of
"MaxList".
.millust begin
extern int MaxList( int how_many, ... );
.millust end
.pc
See the
.book &company C Library Reference
manual description of "va_arg" for a more complete description of
variable number of arguments handling.
.*
.section Conversion from IBM-compatible PC compilers
.*
.np
.ix 'converting to &cmpname' 'from IBM-compatible PC compilers'
.ix 'IBM-compatible PC compilers'
Most of the compilers available for IBM-compatible PCs
have been following the ISO/ANSI standard and, as such,
the majority of programs will not require extensive source changes.
There are problems with programs that use compiler-specific library
functions.
The use of compiler-specific library functions can be dealt with in
two different ways:
.autopoint
.point
use equivalent &cmpname library functions
.point
write your own library functions
.endpoint
.pc
:cmt. A good example is the set of library functions that deal with wild
:cmt. card file specifications.
:cmt. The &cmpname library contains the POSIX conforming functions
:cmt. "opendir", "readdir", and "closedir" but other IBM PC and PS/2
:cmt. compilers use the functions "findfirst" and "findnext".
:cmt. Any program that uses the "findfirst" and "findnext" functions could
:cmt. be changed (in a simple way) to use the functions present in the
:cmt. &cmpname library.
.ix 'predefined macros' '__WATCOMC__'
.ix 'macros' '__WATCOMC__'
.ix '__WATCOMC__'
If portability must be maintained with the other compiler, the
predefined macro
.id "__WATCOMC__"
can be used to conditionally compile the correct code for the &cmpname
compiler.
.np
The default calling convention for the &cmpname compiler is different
from the calling convention used by other compilers for Intel-based
personal computers.
The &cmpname calling convention is different because it will pass some
arguments in registers (thus reducing the overhead of a function call)
rather than pushing all of the arguments on the stack.
The &cmpname compiler is flexible enough to use different calling
conventions on a per function basis.
Converting code from other compilers usually involves recompiling the
C source files and setting up prototypes (to use the older calling
convention) for functions written in assembly language.
For instance, if you have the functions "video_init", "video_put", and
"video_get" written in assembly language, you can use the following
prototypes in any source file which uses these functions.
.ix 'calling conventions' 'cdecl'
.ix 'cdecl' 'calling convention'
.code begin
#include <stddef.h>
extern int cdecl video_init( void );
extern void cdecl video_put( int row,int col,char ch,int attr );
extern char cdecl video_get( int row,int col );
.code end
.pc
The inclusion of the
.fi STDDEF.H
header file defines the "cdecl" calling convention.
The &cmpname compiler will ensure that any calls to these three
functions will adhere to the "cdecl" calling conventions.
The &cmpname compiler will put a trailing underscore "_" character (as
opposed to the beginning of the name for the "cdecl" convention) on
any function names to ensure that the program will not link register
calling convention calls to "cdecl" convention functions (or vice
versa).
If the linker indicates that functions defined in assembler files
cannot be resolved, it could be a result of not prototyping the
functions properly as "cdecl" functions.
.cp 25
.hint
(16-bit applications only)
Most 16-bit C compilers (including &cmpname) have a "large" memory
model which means that four byte pointers are used for both code and
data references.
A subtle point to watch out for involves differences between memory
model definitions of different compilers.
The "cdecl" calling convention allows functions to assume that the DS
segment register points to the group "DGROUP".
The &cmpname large memory model has what is called a "floating DS".
Any function used for the large memory model cannot assume that the DS
segment register points to the group "DGROUP".
There are a few possible recourses.
.autonote
.note
The assembly code could save and restore the DS segment register and
set DS to DGROUP in order to conform to the &cmpname convention.
If there are only a few accesses to DGROUP data, it is advisable to
use the SS segment register which points to DGROUP in the large memory
model.
.ix 'auxiliary pragma' 'loadds'
.ix 'loadds pragma option'
.ix 'pragma' 'loadds option'
.note
The assembly function could be described using a pragma that states
that DS should point to "DGROUP" before calling the function.
.ix 'DS segment register'
.ix 'segment registers' 'DS'
.np
.us #pragma aux _Setcolor parm loadds
.np
In the above example,
.us _Setcolor
is the sample function being described.
.note
.ix 'compile options' 'zdp'
The final alternative would be the use of the "zdp" compiler option.
The "zdp" option informs the code generator that the DS register must
always point to "DGROUP".
This is the default in the small, medium and flat memory models.
Note that "flat" is a 32-bit memory model only.
.endnote
.ehint
.endlevel
.*
.do end
.*
.section What you should know about optimization
.*
.np
.ix 'optimization' 'what you should know'
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
The &lang language contains features which allow simpler compilers to
generate code of reasonable quality.
Register declarations and imbedding assignments in expressions are two
of the ways that C allows the programmer to "help" the compiler
generate good quality code.
An important point about the &cmpname compiler is that it is not as
important (as it is with other compilers) to "help" the compiler.
In order to make good decisions about code generation, the &cmpname
compiler uses modern optimization techniques.
.do end
.if '&lang' eq 'FORTRAN 77' .do begin
The
.book &cmpname User's Guide
contains a detailed description for each of the optimization options
supported by the compiler.
These options allow you to customize the type of code optimizations
that are performed.
For instance, the "OS" option can be used to reduce the size of your
code, but this may affect the execution speed.
To ensure that the speed of the code is optimized, possibly at the
cost of code size, use the "OT" option.
The "OX" option, intended for the maximum number of optimizations,
generates code that is a combination of "OM" (inline math functions),
"OL" (loop), "OT" (time) and the "OR" (instruction scheduling)
optimization options.
Note that when you are using the "OM" option to generate inline math
functions no argument validation will be done for the intrinsic math
functions such as "sin" or "cos".
Consider the needs of your application and select the optimization
options that best meet your requirements.
.do end
.ix 'optimization' 'suggested reading'
.ix 'dragon book'
.cp 12
.hint
The definitive reference on compiler design is the "dragon" book
"Compilers - Principles, Techniques, and Tools", Alfred V. Aho, Ravi
Sethi, and Jeffrey D. Ullman, published by Addison-Wesley, Reading,
Massachusetts, 1986.
The authors of the "dragon" book advocate a conservative approach to
code generation where optimizations must preserve the semantics of the
original program.
The conservative approach is used throughout the &cmpname compiler to
ensure that programmers can use the compiler without worrying about
the semantics of their program being changed.
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
.* there is no "oa" option with FORTRAN
The programmer can request that potentially unsafe optimizations be
performed.
With regard to the "oa" (ignore aliasing) option provided by the
&cmpname compiler, the compiler only ignores aliasing of global
variables rather than ignore aliasing totally like other compilers.
.do end
.ehint
.np
There are certain pieces of information which the compiler cannot
derive from the source code.
.ix 'pragma'
.if '&lang' eq 'FORTRAN 77' .do begin
The "*$pragma" compiler directive is used to provide extra information
to the compiler.
.do end
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
The "#pragma" compiler directive is used to provide extra information
to the compiler.
.do end
It is necessary to have a complete understanding of both &lang and the
machine architecture (i.e., 80x86) before using the powerful pragma
compiler directives.
See the "Pragmas" chapter
.if '&target' ne 'QNX' .do begin
in the
.book &cmpname User's Guide
.do end
for more details.
.np
.ix 'debugging' 'optimized programs'
Debugging optimized programs is difficult because variables can be
assigned to different locations (i.e., memory or registers) in
different parts of the function.
.ix '&cmpname options' 'd1'
.ix '&cmpname options' 'd2'
The "d2" compiler option will restrict the amount of optimization so
that variables occupy one location and can be easily displayed.
It follows that the "d2" option is useful for initial development but
production programs should be compiled with only the "d1" option for
the best code quality.
.ix '&stripname'
Before you distribute your application to others, you may wish to use
the &stripname (&stripcmdup) to remove debugging information from the
executable image on disk thereby reducing disk space requirements.
.ix 'symbolic information'
.ix 'line number information'
.cp 7
.hint
.ix 'debugging'
.ix 'd1'
.ix 'd2'
The "d2" compiler option will generate symbolic
information (for every local variable) and line number information for
the source file.
The "d1" compiler option will only generate line number information
for the source file.
The use of these options determines what kind of information will be
available for the particular module during the debugging session.
.ehint
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
.np
Incorrect programs can sometimes work when compiled with the "d2"
option and not work when compiled with the "d1" option.
One way this sort of problem arises involves local arrays.
.ix 'problems' 'with d2 and d1 options'
.ix 'array subscript errors' 'how they hurt'
.millust begin
void example( void )
{
int i;
int a[10];
for( i = 0; i <= 10; ++i )
a[i] = i;
do_something( a );
}
.millust end
.pc
The "for" loop initializes one too many array elements but the version
compiled with the "d2" option will overwrite the variable "i" without
causing any problems.
The same function compiled with the "d1" option would have the
variable "i" in a register.
The erroneous access of "a[10]" would modify a value that is used to
restore a register when the function returns.
The register would be "restored" with an incorrect value and this
would affect the execution of the function that called this function.
The above example shows how a program can work when compiled with the
"d2" option and stop working when compiled with the "d1" option.
You should always test your program fully with all the modules
compiled with the "d1" option to protect yourself from any surprises.
.do end
.*
.if '&lang' eq 'FORTRAN 77' .do begin
.*
.section Reading a stream of binary data from a file
.*
.np
.ix 'binary data'
.ix 'sequential'
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -