813 lines
30 KiB
Plaintext
813 lines
30 KiB
Plaintext
ZORTECH C++ COMPILER
|
||
|
||
This is version 3.0.
|
||
|
||
Zortech has a policy of continuous improvement to our products. This
|
||
means that changes will have been made since completion of the documentation.
|
||
Therefore, please examine the readme files closely.
|
||
-----------------------------------
|
||
Version : V3.0r1 Release
|
||
Date : July 5, 1991
|
||
|
||
-----------------------------------
|
||
C AND C++ COMPILERS
|
||
The type 'long float' is no longer supported. This is
|
||
to be conformant with ANSI C.
|
||
|
||
The passes ZTC1.EXE and ZTC2.EXE have been dropped.
|
||
If you are running MSDOS with a 386 or 486, ZTC.COM will
|
||
automatically run the 'x' versions of the executable. Otherwise,
|
||
the 'b' versions will be run by default. You can force the use of
|
||
the 'b' versions on a 386 or 486 by using the -b flag explicitly.
|
||
|
||
When the -e switch is used, source file and line numbers now
|
||
are printed with error messages, rather than preprocessed
|
||
line numbers and the file "preprocessed".
|
||
|
||
_loadds and _export now work on member functions.
|
||
|
||
The way floats and doubles are returned from Pascal and C++
|
||
functions has been changed. Instead of the value being
|
||
returned in the CPU registers, it is returned on the stack
|
||
in the same way that structs are returned. This is compatible
|
||
with the way MSC returns floats and doubles for Pascal and
|
||
FORTRAN functions. The behavior of Pascal and FORTRAN
|
||
functions is identical in MSC and ZTC/C++.
|
||
|
||
The way floats and doubles are returned from C functions was
|
||
not modified because doing that would make it no longer
|
||
reentrant, a feature that many customers require.
|
||
|
||
10 byte long doubles are not supported in ZTC/C++. Long doubles
|
||
are 8 bytes. In the future we will probably make them 10
|
||
bytes.
|
||
|
||
With the -s flag to add stack overflow checking, the
|
||
function chkstk() is always called now instead of only
|
||
being called if there are local variables. This enables more
|
||
accurate checking and provides a hook for profilers who
|
||
need to know when functions are called.
|
||
|
||
Bit fields can now be any integral type, though they are always
|
||
treated as the unsigned versions of the integral types.
|
||
|
||
Conversions of ints directly to far pointers is a syntax error
|
||
instead of a warning. If you want to do this, cast the int to
|
||
a long before casting it to a pointer.
|
||
|
||
The following cast:
|
||
long l;
|
||
char near *p;
|
||
l = (long) p;
|
||
is handled like:
|
||
l = (long)(char far *)p;
|
||
instead of like:
|
||
l = (long)(unsigned)p; /* 0 fill high 16 bits */
|
||
The conversion of a far pointer to a long and vice versa
|
||
is done as a 'paint', i.e. no change in the bit pattern
|
||
occurs.
|
||
-----------------------------------
|
||
C++ COMPILER
|
||
If the -A switch is used, static class data members now must
|
||
have a definition elsewhere somewhere in the program. Without
|
||
-A, an initialization of 0 is provided if none is provided,
|
||
unless a constructor is required.
|
||
|
||
The #ident pragma is recognized and ignored. This is for
|
||
compatibility with some Unix software.
|
||
|
||
The predefined macros SPTR and LPTR have been removed. This is
|
||
because windows.h uses them, and because of their
|
||
Ansi incompatibility. If you need them, you can use the
|
||
following equivalent:
|
||
|
||
#if M_I86SM || M_I86MM
|
||
#define SPTR 1
|
||
#else
|
||
#define LPTR 1
|
||
#endif
|
||
|
||
The -P switch now causes global variables to have pascal
|
||
name mangling (converting name to upper case) as well as
|
||
function names. This is for improved compatibility with MSC.
|
||
However, be careful that if you are communicating with the
|
||
Zortech runtime library via global variables such as _8087,
|
||
_stack, and _okbigbuf, be sure to declare them as _cdecl,
|
||
as in:
|
||
int _cdecl _8087;
|
||
to ensure that they will link properly with the runtime library.
|
||
-----------------------------------
|
||
C COMPILER
|
||
// comments are now accepted for compatibility with much
|
||
existing Windows code.
|
||
-----------------------------------
|
||
SEGMENT CONTROL
|
||
There are now several ways to control the code segment name(s)
|
||
in your object files.
|
||
|
||
1. The old way, which is use the name generated by the compiler.
|
||
|
||
2. Use PATCHOBJ to modify the segment names in the .OBJ file.
|
||
|
||
3. Use the -NTcsname switch, which sets the code segment name
|
||
to csname. Note that there is no space between -NT and csname.
|
||
|
||
4. Use the -NS switch, which causes a new code segment to be
|
||
started each time a global far function is encountered.
|
||
(Be careful using near functions with this, the near functions
|
||
must immediately follow any global function which calls them,
|
||
and cannot be called by more than one global function (because
|
||
near functions cannot cross segment boundaries)).
|
||
The name of the segment is the name of the function with _TEXT
|
||
appended.
|
||
|
||
5. Use the #pragma:
|
||
#pragma ZTC cseg csname
|
||
which causes subsequent code to be placed in the segment
|
||
csname. When used with -NS, the -NS switch overrides the
|
||
pragma for global far functions.
|
||
|
||
The -NT, -NS and #pragma ZTC cseg can all be used independently
|
||
or in any combination.
|
||
|
||
Segment name control is an advanced technique usually used
|
||
when optimizing very large Windows and OS/2 protected mode
|
||
programs. The idea is to group functions which frequently
|
||
call each other into the same segment.
|
||
-----------------------------------
|
||
386ASM AND 386LINK
|
||
ZTC will now run .asm files through 386ASM instead of MASM
|
||
if -mp or -O is used, and assembling for the 386 or 486.
|
||
|
||
ZTC and MAKE can now handle arbitrarilly long command lines
|
||
for 386ASM and 386LINK.
|
||
-----------------------------------
|
||
OS/2 COMPILER
|
||
ZTC1.EXE and ZTC2.EXE have been dropped, ZTC1B.EXE and ZTC2B.EXE
|
||
are now always run, regardless of the -b switch setting on
|
||
ZTC.COM.
|
||
-----------------------------------
|
||
ZTC.COM
|
||
The -L switch has been extended. If there is a parameter following
|
||
the -L, it is assumed to be a switch or a path, which is added
|
||
to the linker command line. For instance,
|
||
ZTC test -L/packcode -L\test\prog\
|
||
will add the switch /packcode on the linker command, and will
|
||
add the library search path \test\prog\ to the command. Note that
|
||
MS-LINK requires the trailing \ on path commands.
|
||
|
||
.ASM extensions are now tried *after* .CPP and .C default extensions.
|
||
|
||
.CC and .C++ are now recognized as C++ source filename extensions.
|
||
|
||
.EXE and .COM files on the command line are now taken to be
|
||
the executable program file name. A .COM extension will cause
|
||
EXE2BIN to be run (same as -mt switch).
|
||
|
||
dos_abs_disk_read/write now work with DOS 4.
|
||
-----------------------------------
|
||
MAKE
|
||
Now accepts a sequence of rule flags, instead of only
|
||
allowing one.
|
||
|
||
SET commands can now be used to set environment variables for
|
||
executed programs.
|
||
-----------------------------------
|
||
C LIBRARY
|
||
Added the ANSI C functions:
|
||
|
||
mblen
|
||
mbtowc
|
||
wctomb
|
||
mbstowcs
|
||
wcstombs
|
||
tmpfile
|
||
|
||
The old way of doing wild card expansion on the command line
|
||
was to link in the file _main$(MODEL).obj. This is no longer
|
||
necessary, just add the line
|
||
|
||
WILDCARDS
|
||
|
||
at file scope level in one of your source files. WILDCARDS is
|
||
defined in DOS.H. The old method will be dropped probably in
|
||
the next release.
|
||
|
||
Sometimes it is convenient determine what type of executable
|
||
a program is at runtime rather than compile time. Especially
|
||
since Zortech supports so many different kinds of executables.
|
||
This feature can aid, for instance, in making fewer libraries
|
||
that still support all the exe types.
|
||
In dos.h, there is the global:
|
||
extern unsigned short _cdecl _exe_type;
|
||
which is set to one of the following:
|
||
|
||
EXE_DOS MSDOS
|
||
EXE_DOS16RM Rational 286 DOS Extender
|
||
EXE_ZPM ZPM 286 DOS Extender
|
||
EXE_PHAR386 Pharlap 386 DOS Extender
|
||
EXE_DOSX DOSX 386 DOS Extender
|
||
EXE_WINDOWS Windows 3
|
||
EXE_OS2 OS/2 1.x
|
||
EXE_SCOUNIX SCO Unix
|
||
|
||
alloca() has been implemented. alloca() cannot be used inside
|
||
functions that have the Windows prolog/epilog code in them.
|
||
-----------------------------------
|
||
C++ LIBRARY
|
||
This has now been combined with the C library. There no longer
|
||
are separate C++ libraries.
|
||
|
||
If you are linking with C++ .OBJ files generated by older
|
||
versions of ZTC++, the library PLx.LIB will not be found. The
|
||
solutions are:
|
||
o Recompile the code with ZTC++ 3.0.
|
||
o Link with the /NOD switch, and specify ZLx.LIB on
|
||
the command line to the linker.
|
||
o Use ZORLIB to create a PLx.LIB library with nothing
|
||
in it.
|
||
o Use PATCHOBJ to remove the default library names from
|
||
the .OBJ files.
|
||
-----------------------------------
|
||
ARRAYS LARGER THAN 64K
|
||
|
||
Frequently it is necessary to have arrays that are larger than 64K,
|
||
for instance:
|
||
char array[100000]; // 100,000 bytes
|
||
double values[10][1000]; // 10*1000*8 == 80,000 bytes
|
||
This cannot be directly done with 16 bit compilers. A portable
|
||
alternative is to construct an array of pointers to arrays, where
|
||
each unit is less than 64k in size. Our examples above become:
|
||
|
||
char *array[2];
|
||
#define array(i) (array[(i) & 1][(i) >> 1])
|
||
|
||
double *values[10];
|
||
|
||
This needs to be in one of the large data models, C, L, R or V.
|
||
These cannot be statically allocated, so we turn to calloc to initialize
|
||
them to all 0s:
|
||
|
||
main()
|
||
{
|
||
int i;
|
||
|
||
for (i = 0; i < 2; i++)
|
||
array[i] = (char *) calloc(100000/2,sizeof(char));
|
||
|
||
for (i = 0; i < sizeof(values)/sizeof(values[0]); i++)
|
||
values[i] = (double *) calloc(1000,sizeof(double));
|
||
|
||
...
|
||
}
|
||
|
||
To access an element of array[], instead of array[i], use the syntax:
|
||
|
||
long i;
|
||
|
||
array(i) = array(i + 10);
|
||
|
||
Note that the macro can be used both as an lvalue or an rvalue. Similarly,
|
||
for values:
|
||
|
||
int i,j;
|
||
|
||
values[i][j] = values[i][j] + 6.7;
|
||
|
||
It probably will not be necessary to deallocate the memory used for the
|
||
arrays, if they are used for the duration of the program. DOS will deallocate
|
||
them when the program terminates.
|
||
|
||
The methods used are not only portable ANSI C, they are also
|
||
frequently faster than using the so-called huge arithmetic. They are
|
||
directly portable to a 32 bit compiler.
|
||
-----------------------------------
|
||
HUGE POINTERS
|
||
|
||
Sometimes it becomes inevitable that one must deal with objects larger
|
||
than 64k, because they are returned by the operating system or some
|
||
third party library over which one has no control. Here are a set
|
||
of techniques for dealing with those rare cases in a portable manner.
|
||
|
||
Huge pointers are pointers that point into and can manipulate a
|
||
contiguous block of memory that is larger than 64k. Recall that
|
||
a far pointer on 80X86 CPUs consist of a 16 bit segment and a 16
|
||
bit offset. Thus, up to 64k can be addressed by adjusting the offset
|
||
alone. This is how far pointers work. To deal with blocks larger
|
||
than 64k, the segment must also be manipulated.
|
||
|
||
A moment's reflection will show that there are only three operations
|
||
that need to be done with a huge pointer. That is, adding a (possibly
|
||
negative) offset to it, comparing it with another huge pointer, and
|
||
computing the difference between it and another huge pointer. The
|
||
names of these functions are:
|
||
|
||
hugeptr_add
|
||
hugeptr_cmp
|
||
hugeptr_diff
|
||
|
||
These functions and macros are made available by #include'ing hugeptr.h.
|
||
If the compile is for 32 bit code, the functions become direct pointer
|
||
manipulation on 32 bit near pointers.
|
||
|
||
Example:
|
||
#include <hugeptr.h>
|
||
|
||
/* A version of strlen() that works with strings > 64k in length */
|
||
|
||
long hstrlen(const char _far *h)
|
||
{ const char _far *hend;
|
||
|
||
hend = *h;
|
||
while (*hend)
|
||
hend = (char _far *) hugeptr_add(hend,1);
|
||
return hugeptr_diff(hend,h);
|
||
}
|
||
-----------------------------------
|
||
RATIONAL SYSTEMS' 286 DOS EXTENDER
|
||
The following files are no longer distributed by Zortech:
|
||
|
||
DOS16.H
|
||
RUN.MAC
|
||
DOS16LIB.C
|
||
PML.ASM
|
||
ZRL.LIB
|
||
MAKEFILE.RAT
|
||
|
||
Instead, they or the equivalent will be supplied by Rational
|
||
when you purchase their extender.
|
||
|
||
There is no separate CR.OBJ needed anymore to link a Rational
|
||
executable, instead specify ZRL.LIB in the list of libraries
|
||
to the linker, and be sure to use the /NOE switch when using
|
||
Microsoft LINK.
|
||
|
||
Specific instructions on using Rational's extender with Zortech
|
||
C/C++ will be supplied by Rational.
|
||
-----------------------------------
|
||
OLD STREAMS
|
||
The old C++ 1.2 stream library, stream.hpp, has been moved out
|
||
of the main libraries and into separate libraries, as they are
|
||
incompatible with new streams. If you are using old streams, the
|
||
old stream library must be explicitly linked in, or specified on
|
||
the command line to ZTC.COM. The libraries are:
|
||
|
||
For MSDOS, OS/2 and Windows:
|
||
|
||
oldstrs.lib S model
|
||
oldstrm.lib M model
|
||
oldstrc.lib C model
|
||
oldstrl.lib L model
|
||
|
||
For MSDOS:
|
||
|
||
oldstrl.lib R,Z models
|
||
oldstrv.lib V model
|
||
|
||
For Pharlap and DOSX 386 extenders:
|
||
|
||
oldstrx.lib P,X models
|
||
|
||
Example:
|
||
ZTC test.cpp \zortech\lib\oldstrs.lib
|
||
|
||
We recommend that you convert to new streams, as the old streams
|
||
are obsolete and may get dropped in future versions of ZTC++.
|
||
-----------------------------------
|
||
DGROUP DATA SEGMENT OVERFLOWS
|
||
Many people with large programs run out of space in the
|
||
default data segment DGROUP. The solution is to move some
|
||
data out of DGROUP into other segments. Possible ways are:
|
||
1. Compile with the -R switch which causes switch statement
|
||
tables to be placed in the code segment rather than
|
||
DGROUP.
|
||
2. For C++ programs, use the -NV switch to place virtual
|
||
function pointer tables in far data segments.
|
||
3. Declare statically allocated data as far, i.e.:
|
||
int far array[100];
|
||
Data declared as far should be data that is both relatively
|
||
large and is accessed relatively infrequently, as the
|
||
segment register juggling required to access it is rather
|
||
expensive.
|
||
|
||
If another module should reference far static data, be
|
||
sure and declare it as far, as in:
|
||
extern int _far array[];
|
||
Otherwise, the compiler will assume that it is in the default
|
||
data segment DGROUP. Note that this is different from MSC6's
|
||
implementation, where extern data is not assumed to be in
|
||
DGROUP. Although our implementation involves more work on
|
||
the programmer's part (putting _far in the right places), we
|
||
feel that the fine control this offers makes it more than
|
||
worthwhile in high-performance applications. It's also true
|
||
that most applications need less than 64k of static data,
|
||
and so needn't pay any unnecessary penalty for assuming that
|
||
extern data is not accessible via DS.
|
||
-----------------------------------
|
||
WINDOWS SUPPORT
|
||
|
||
The -mw switch that specifies DS!=SS is only needed for the following types of code:
|
||
A) Windows Dynamic Link Libraries (DLLs).
|
||
B) OS/2 DLLs.
|
||
C) OS/2 threads.
|
||
|
||
Currently, class objects can only be created on the near heap for S and M
|
||
models, and only on the far heap for C and L models. Objects cannot be
|
||
created in __ss or __handle space.
|
||
|
||
If you are calling virtual member functions in Windows, and the
|
||
definition of the virtual member function is in your app, and the call
|
||
is from a DLL, the following problem occurs:
|
||
|
||
1. If _loadds (or -mu) is not used for the function, DS will probably not have
|
||
the right value in it when the function is called.
|
||
|
||
2. If _loadds is used (or -mu), DS will have the right value in it
|
||
*AS LONG AS THERE IS ONLY ONE INSTANCE OF THE APP RUNNING*. Second
|
||
instances will have the DS set to the value for the first instance.
|
||
|
||
There isn't any clean solution to this. The virtual function is what
|
||
Windows calls a 'callback function'. Callback functions cannot be called
|
||
directly from the app, they can only be called via a pointer returned
|
||
by MakeProcInstance(). They also must be compiled with the Windows
|
||
prolog/epilog code in (the -W switch). This is impractical for virtual
|
||
functions. Therefore, do not reference static or global data in
|
||
a virtual function meant to be called from a DLL, or use near pointers.
|
||
-----------------------------------
|
||
SYMBOLIC DEBUG INFO
|
||
Limitations and problems:
|
||
o In order to conserve the size of the symbol table,
|
||
typedefs and enums are not emitted. Only the minimal
|
||
type information for variables actually used is emitted.
|
||
o Because the optimizer moves variables and sections of code
|
||
around, there becomes only one scope per function. Thus,
|
||
avoid using the same variable names in nested scopes
|
||
if you want to use the debugger on them.
|
||
o Use the -S switch to cause the code generator to always
|
||
generate a stack frame for each function if you want
|
||
symbolic debugging. Most debuggers seem to expect this.
|
||
ZTC.COM will automatically invoke -S if the -g or -gs
|
||
switch was specified.
|
||
-----------------------------------
|
||
COMPILER VERSIONS
|
||
There are two ways to find the version of the compiler you are using:
|
||
1. Compile a file with -v.
|
||
2. Run ZTC1B, etc., with no arguments.
|
||
|
||
-----------------------------------
|
||
LIBRARY SOURCE
|
||
Added files to support ROM code development:
|
||
ROMASM BAT Replace ASM module in rom libs
|
||
ROMC BAT Replace C module in rom libs
|
||
CROM ASM Sample ROM startup code
|
||
The BUILDLIB.BAT file can be used to make all four rom libraries.
|
||
-----------------------------------
|
||
C PROGRAMMING TOOLS
|
||
Please look in the subdirectory SAMPLE for a description of these
|
||
useful utilities.
|
||
-----------------------------------
|
||
HEAP IS CORRUPTED
|
||
This error message appears sometimes when running programs
|
||
compiled with Zortech. This message is generated by the
|
||
library function free(), caused by:
|
||
1. Passing free() a pointer not generated by malloc, calloc or
|
||
realloc.
|
||
2. Free'ing the same pointer twice.
|
||
3. A wild pointer has trashed the heap's data structures.
|
||
|
||
If you are writing C code, the mem package is designed to
|
||
help track down such errors.
|
||
|
||
A common cause of this in C++ programs is when classes contain a
|
||
member that is a dynamically allocated pointer to something. If
|
||
there is no copy constructor, the compiler generates a memberwise
|
||
copy, resulting in two instances with the same pointer in them.
|
||
Destructing both results in case 2 above.
|
||
For example:
|
||
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
|
||
struct X {
|
||
char *p;
|
||
X(char *s) { p = strdup(s); }
|
||
~X() { free(p); }
|
||
};
|
||
|
||
main()
|
||
{ X x("hello");
|
||
X y = x; // invoke copy constructor
|
||
x = y; // invoke X::operator=(X&)
|
||
}
|
||
|
||
This is guaranteed to generate the "Heap is corrupted" message.
|
||
To fix the code, add these member functions to X:
|
||
|
||
X(X& x) { p = strdup(x.p); }
|
||
|
||
X& operator =(X& x)
|
||
{ free(p);
|
||
p = strdup(x.p);
|
||
return *this;
|
||
}
|
||
-----------------------------------
|
||
VIRTUAL FUNCTION POINTER TABLES
|
||
A table of pointers to functions is created for each class that
|
||
has virtual functions or is derived from a class with virtual
|
||
functions. Because of separate compilation, sometimes redundant
|
||
copies of the tables are created, even leading to excessive
|
||
consumption of space in DGROUP. It turns out that the only time
|
||
the code needs a virtual function pointer table (vtbl) is within
|
||
the body of a constructor. So a vtbl for a class is only actually
|
||
generated when the body of a constructor that needs a vtbl is
|
||
instantiated. A maximum of one vtbl per class per object module
|
||
is generated.
|
||
|
||
This suggests a technique for minimizing vtbl generation:
|
||
1. Avoid inline constructors.
|
||
2. Group all the definitions for constructors for a class into
|
||
one source file.
|
||
This will create a maximum of one vtbl per class per program.
|
||
|
||
Other C++ implementations use command line switches to cause
|
||
vtbls in some modules to be global, in others external. This
|
||
can get rather complex, the above technique is simpler and more
|
||
reliable.
|
||
-----------------------------------
|
||
FLASH GRAPHICS
|
||
|
||
The FG support for the IBM 8514A is actually for the IBM 8514A API.
|
||
Thus, any display that conforms to the API definition will work with
|
||
FG. Another consequence of this is that the FG detect logic looks for
|
||
the API, *not* the 8514A itself. The API is actually a TSR supplied by
|
||
IBM with the 8514A, and must be run before the FG application is run.
|
||
|
||
===========================================================================
|
||
EXISTING PROBLEMS AND WORKAROUNDS
|
||
===========================================================================
|
||
|
||
************************ MAKE ****************
|
||
-----------------------------------
|
||
Should have a -k switch to cause make to continue after errors
|
||
occur attempting to make targets not depending on the one that failed.
|
||
-----------------------------------
|
||
Make cannot figure out more than one level of implicit rules.
|
||
I.e. this doesn't work:
|
||
|
||
.c.obj: ;ztc -c $<
|
||
.obj.exe: ;ztc $<
|
||
hello.exe: hello.c
|
||
|
||
****************** C COMPILER ****************
|
||
-----------------------------------
|
||
The macros:
|
||
#define STR(a) NXSTR(a)
|
||
#define NXSTR(a) #a
|
||
#define A 1
|
||
if (STR(A)[0] == '1')
|
||
result in:
|
||
if ("A"[0] == '1')
|
||
instead of:
|
||
if ("1"[0] == '1')
|
||
-----------------------------------
|
||
Conversions between doubles and unsigned longs are handled
|
||
as if they are conversions between doubles and signed longs.
|
||
-----------------------------------
|
||
Expecting void functions to return values gets ZTC2 bugs in the following
|
||
case:
|
||
|
||
{
|
||
extern void func();
|
||
|
||
i = h() ? g() : func();
|
||
}
|
||
-----------------------------------
|
||
The preprocessor line
|
||
|
||
#line 47 "FILE.C"
|
||
|
||
does not set the module name to file.c.
|
||
-----------------------------------
|
||
If there is an error writing the .OBJ file, the .OBJ file is not
|
||
deleted. If the error is because the disk is full, there remains a
|
||
partial corrupted .OBJ file.
|
||
-----------------------------------
|
||
The type 'long double' is not distinguished from type 'double'.
|
||
-----------------------------------
|
||
A near pointer is converted to a far pointer by putting DS, SS or CS into
|
||
the segment portion as appropriate. The bug is if the near pointer is NULL,
|
||
the resulting far pointer gets a non-zero segment value! When converting,
|
||
always testing for 0 before loading the segment would cause a lot of
|
||
inefficiencies. Note that MSC 5.1 has the same bug, I haven't checked
|
||
TC or BCC for it.
|
||
|
||
****************** C++ COMPILER ****************
|
||
-----------------------------------
|
||
All the current bugs in the C compiler (!).
|
||
-----------------------------------
|
||
When the compiler internally generates an X& X::operator=(X&), and
|
||
X has a virtual base class V that appears N times in the inheritance DAG,
|
||
the function V& V::operator=(V&) is called N times instead of once.
|
||
-----------------------------------
|
||
When the compiler internally generates an X& X::operator=(X&), and
|
||
X has a member that is an array of class Y, a bit copy is done of the
|
||
array instead of a loop calling Y& Y::operator=(Y&).
|
||
-----------------------------------
|
||
Inline functions that contain any whiles, dos,
|
||
fors or switches are not inlined. The code will still compile and
|
||
execute correctly, however. This is not a bug.
|
||
-----------------------------------
|
||
If a class name is hidden in a lower level scope, you still
|
||
can't access it even if you prefix it with 'struct' or 'class'.
|
||
-----------------------------------
|
||
To call a function via a pointer to member, you must use exactly
|
||
one set of parentheses:
|
||
a = (p->*mfp)(args...); // works
|
||
a = ((p->*mfp))(args...); // bug: gives syntax errors
|
||
b = p->*mfp; // what is this supposed to mean?
|
||
-----------------------------------
|
||
You cannot cast pointers to members to/from pointers to virtual base class
|
||
members. This produces a syntax error if tried.
|
||
-----------------------------------
|
||
Pointers to data members can be explicitly cast to ints. Since they are
|
||
implemented as ints, this seemed reasonable. It's not portable, but
|
||
is useful in special contexts (like debugging!).
|
||
|
||
Pointers to function members can be explicitly cast to regular pointers
|
||
to functions. This is also non-portable.
|
||
-----------------------------------
|
||
Pointers to function members, even when they should compare equal, may
|
||
not. This occurs when a thunk is generated to do things like adjust the
|
||
this pointer offset, or call a virtual member function. If the thunks
|
||
are generated in different files, the member pointers will compare
|
||
different (because just the addresses are compared).
|
||
-----------------------------------
|
||
The anachronistic member access syntax on the last page of the C++ book:
|
||
int cl.fct() { /* ... */ }
|
||
is not supported. Use instead:
|
||
int cl::fct() { /* ... */ }
|
||
-----------------------------------
|
||
Compiler should issue warning when a non-virtual method in a sub-class hides
|
||
a virtual method in the base class. (Tony Hagen, James Coggins,
|
||
Bjarne Stroustrup, et. al. suggest it.) The other way around, too.
|
||
-----------------------------------
|
||
Variadic cdecl functions that return structures return them in a static
|
||
temporary rather than on the stack, thus they are not reentrant and more
|
||
than one cannot be used in the same expression.
|
||
-----------------------------------
|
||
If a class or a struct has no tag name, the compiler will generate one of
|
||
the form "_C%d", where %d increments with each new name generated. This
|
||
is necessary for the name mangling to work. Unfortunately, if you have
|
||
structs like this defined in header files, and include the files in
|
||
different orders in different files, the names will come out different.
|
||
This can cause errors at link time due to the name mangling and typesafe
|
||
linkage not lining up. Because of this, the compiler generates a warning
|
||
if there is no tag name and the tag name is needed for name mangling
|
||
purposes.
|
||
-----------------------------------
|
||
struct s { f(); };
|
||
static s::f() {} // diagnosed as an error by cfront
|
||
|
||
ZTC++ allows member functions to be local to a file, i.e. static. Cfront
|
||
does not allow this.
|
||
-----------------------------------
|
||
Conditional expressions cannot be lvalues, as in:
|
||
(a ? b : c) = 7;
|
||
are not allowed.
|
||
|
||
****************** C LIBRARY ****************
|
||
-----------------------------------
|
||
The int package uses a local stack for the interrupt service routine (isr).
|
||
If there are overlapping interrupts to the same isr, the program will
|
||
crash because the stacks overlap!
|
||
If you use 0 for the stack size parameter to int_intercept(), no local
|
||
stack will be allocated for the isr. Thus, overlapping interrupts have
|
||
a chance of working (if the original stack is big enough).
|
||
-----------------------------------
|
||
The stat() function uses findfirst(). So if you are in the middle of a
|
||
findfirst-findnext sequence, you cannot use stat().
|
||
|
||
****************** BLINK ****************
|
||
-----------------------------------
|
||
If a .OBJ file is corrupted, BLINK may crash instead of issuing
|
||
an error message.
|
||
-----------------------------------
|
||
|
||
******************** BUG REPORTS **************************
|
||
|
||
Occasionally, you may run across a suspected problem with the compiler.
|
||
If you send in a bug report, please do the following:
|
||
1. Try to determine the smallest possible program that exhibits the problem.
|
||
Sending in a 10,000 line program with a message that "it doesn't work"
|
||
doesn't help much. Also, frequently the process of determining that
|
||
smallest program reveals the problem to be something other than a compiler
|
||
bug. At the least, an easy workaround to keep you going becomes obvious.
|
||
Compiling with the -v switch can help a lot in isolating the problem
|
||
down.
|
||
2. Include all the #include'd .h and .hpp files. Better yet, boil it all
|
||
down to 1 source file that demonstrates the problem without #include'ing
|
||
anything.
|
||
3. Include a READ.ME file describing the problem, and what command was
|
||
issued to the compiler to cause it.
|
||
4. Check to make sure it isn't one of the following problems. A large
|
||
number of the bug reports we get are really variations on these,
|
||
even experts frequently make these mistakes:
|
||
|
||
Common problem #1: Assigning beyond the end of alloc'd data.
|
||
|
||
p = malloc(4);
|
||
for (i = 0; i <= 4; i++)
|
||
p[i] = value;
|
||
|
||
The bug is that when i==4, assigning to p[4] will cause a
|
||
probable program crash.
|
||
|
||
Another common manifestation of this is:
|
||
|
||
p = malloc(strlen(s));
|
||
strcpy(p,s); /* didn't leave room for terminating 0! */
|
||
|
||
Common problem #2: Returning a reference to a variable that goes out of scope.
|
||
|
||
int &func()
|
||
{ int a;
|
||
...
|
||
return a;
|
||
}
|
||
|
||
Common problem #3: Expecting that \ line splicing does not occur in a // comment.
|
||
|
||
According to ANSI C para. 2.1.1.2, \ line splicing occurs in
|
||
translation phase 2, that is, *before* comment processing is done.
|
||
Therefore, // comments ending in a \ will splice lines, as in:
|
||
|
||
// This is a comment \
|
||
printf("This should never print.\n");
|
||
|
||
Since the ANSI C++ people say that they intend to 'drop in'
|
||
the ANSI C preprocessor, this is the correct way it should work.
|
||
Unfortunately, some C++ compilers do not do this correctly, and
|
||
the split seems to be about 50-50. Therefore, currently we
|
||
recommend that // comments should never end in a \.
|
||
|
||
We've also seen some code that used some nice-looking comments like:
|
||
|
||
//--------------------------\\
|
||
|
||
This is best avoided.
|
||
|
||
Common problem #4: Mixing old style definition with ANSI C prototype
|
||
|
||
The following is *NOT* a bug, it's ANSI C:
|
||
|
||
extern int func(char);
|
||
int func(c)
|
||
char c;
|
||
{
|
||
^
|
||
"test.c", line 5 Syntax error: type of 'c' does not match function prototype
|
||
Had: <int>
|
||
and: <char>
|
||
}
|
||
|
||
Old style parameter types undergo integral promotions before
|
||
comparing them against the prototype. The old style "char c;"
|
||
is interpreted as "c is passed as an int, but interpret it as
|
||
a char in func". If you want it to be a char, define func as:
|
||
int func(char c) { ... }
|
||
|
||
************************ ZORTECH ELECTRONIC SUPPORT *************************
|
||
|
||
Zortech operates a free bulletin board system for Zortech customers
|
||
and anyone else who is interested in C++. There are many files of interest to C++
|
||
programmers to download, and message areas where you can have conversations
|
||
with other C++ users. The phone numbers are:
|
||
|
||
(206) 822-6907 USA
|
||
081 855 3286 England
|
||
|
||
We also have a conference on BIX, to join type:
|
||
|
||
j zortech
|
||
|
||
In Europe, we also have a conference on CIX, again type
|
||
|
||
j zortech
|
||
|
||
For those with access to unix email, we have a Zortech mailing list. To
|
||
join in, send mail to:
|
||
|
||
ztc-list-request@zortech.com
|
||
|
||
Other unix email addresses are:
|
||
|
||
sales@zortech.com For pricing questions and orders
|
||
ztc-bugs@zortech.com For sending in bug reports
|
||
ztc-list@zortech.com For posting to the Zortech mailing
|
||
list
|
||
of old style function definition
|
||
parameter types.
|
||
|
||
-----------------------------------
|
||
EOF
|