Category : C Source Code
Archive   : TCPBUGS2.ZIP
Filename : BUGS.TXT

 
Output of file : BUGS.TXT contained in archive : TCPBUGS2.ZIP
==========================
borland/long.messages #32, from lbenner, 36556 chars, Wed Jan 9 18:50:18 1991
--------------------------

We at Borland have responded to the items in the uploaded list.

TITLE: CLINE TC++ Bug List.
From tessi!mntgfx!uunet!cheetah.ece.clarkson.edu!cline Sat Dec 1 01:27:03
1990
Return-Path:
Received: from tessi.UUCP by ims.UUCP (4.0/IMS-gateway/V1.3)
id AA18758; Sat, 1 Dec 90 01:27:02 PST
Received: from mntgfx.UUCP by tessi; Fri, 30 Nov 90 23:38:32 PST
Received: by pdx.MENTOR.COM ( 5.52 (84)/smail2.5/09-24-87/Mentor)
id AA11354; Fri, 30 Nov 90 22:31:55 PST
Received: from omnigate.clarkson.edu by uunet.UU.NET (5.61/1.14) with SMTP
id AA05366; Sat, 1 Dec 90 00:56:19 -0500
Received: from cheetah.ece.clarkson.edu by omnigate.clarkson.edu id aa23598;
1 Dec 90 0:35 EST
Received: by cheetah.ece.clarkson.edu (4.1/SMI-4.0)
id AA05334; Sat, 1 Dec 90 00:31:19 EST
Date: Sat, 1 Dec 90 00:31:19 EST
From: Marshall Cline
Message-Id: <[email protected]>
To: ericm%[email protected]
Subject: Monthly posting of Turbo-C++ bug list
Status: R

Name: Turbo-C++ bug list (bug-list-version 1.01.4)

Products: Borland Turbo-C++ 1.00
Borland Turbo-C++ 1.01

Author: Marshall P. Cline
ECE department
Clarkson University
Potsdam, NY 13676

Voice: 315-268-3868
Secretary: 315-268-6511
FAX: 315-268-7600

Internet: [email protected]
Alternate: [email protected]
Bitnet: BH0W@CLUTX
UUnet: uunet!clutx.clarkson.edu!bh0w

Copyright: The Author releases this to the Public Domain

NO WARRANTY: This list is distributed with NO WARRANTY
WHATSOEVER.
It is NOT guaranteed that this information is free
from error; parts of this were donated by others, etc.

Availability: This is freely available via anonymous ftp
from: sun.soe.clarkson.edu [128.153.12.3]
in the file: ~ftp/pub/Turbo-C++/bug-report

Revisions: BugList-Date BugList-Version
11 Jun 90 1.00.1
09 Aug 90 1.00.2
14 Aug 90 1.00.3
29 Aug 90 1.00.4
20 Sep 90 1.00.5
14 Nov 90 1.01.1 (some TC++ v.1.01 info added)
21 Nov 90 1.01.2 (some responses from Borland)
26 Nov 90 1.01.3
30 Nov 90 1.01.4

Copyright:
This file is PUBLIC DOMAIN (including the contained code fragments).
That means no one (including myself) can restrict its use/distribution.
In particular, you can't copyright it. No one can. Not even me.

Contributions:
If you have a TC++ bug to report, please email to the above addresses.
But please try to find/send a work-around to the problem/bug.
Also please explicitly state that your comments/code are public domain.

The ``Borland says'' comments are from:
borland/long.messages #27, from lbenner, 9387 chars, Fri Nov 9 18:58:20
1990
TITLE: Borland's Comments to Emartinson's Bug List
Borland has added comments to the items listed in this file
originally posted as #25 from emartinson.
Lori Borland

=============================================================================
=============================================================================

Severity: not serious
Versions: occurs in both TC++ 1.00 and 1.01

Several classlib\include\*.h have #include "foo.h" rather than .
This will only cause a problem if you have an indentically named header file
in your current working directory (#include "file.h" starts in current dir,
then searches the "standard places"; only searches standard places).
Note that TC++ by default doesn't find the classlib header files; if you want
it to, add the line to turboc.cfg: -IC:\TC\CLASSLIB\INCLUDE

Borland's Response:

This is true. We have passed the suggestion to have the classlib header
files be included with a consistent method.
-----------------------------------------------------------------------------

Severity: not serious inconsistency in classlib's header files
Versions: occurs only in TC++ 1.00; fixed in 1.01

Some include files have #ifndef __FILENAME_H, others have #ifndef _FILENAME_H.
(inconsistent #leading underscores). See for example sortable.h vs set.h,
etc.

Obviously this won't cause any problems; it's just an inconsistency that could
be corrected as time permits.

-----------------------------------------------------------------------------

Severity: missed feature
Versions: occurs in both TC++ 1.00 and 1.01

TCCNVT.EXE (the configuration file converter) isn't in the distribution.

Borland's Response:

This is true. The developers are aware of the inconsistency.

-----------------------------------------------------------------------------

Severity: bug in support tool
Versions: occurs in both TC++ 1.00 and 1.01
[Borland says 1.01 fixed this, but my 1.01 still exhibits this behavior]

`make -n' looks for and reads `builtins.mak' ONLY if it's in the current dir.
Naturally this is a bug, since make can't give an accurate picture of what a
real `make' would do without the macros and implicit rules in `builtins.mak'.

>Craig Orsinger/[email protected]/R&DAssoc/3625 Perkins L SW/Tacoma,WA
98499:
>This also happens if you call "make" from your makefile. I don't know if this
>occurs if the makefile and "make" program are on the same disk partition, but
>it definitely does when they are not. My work-around was to use the new
>"search path" feature of make to tell it where the "builtins.mak" file is.

Borland's Response:

We replicated this in both 1.0 and 1.01, and it should be fixed in a
future version.

-----------------------------------------------------------------------------

Severity: not serious
Versions: occurs in both TC++ 1.00 and 1.01

always includes which slows compilation some. In fact
doesn't need `NULL', and only needs memcpy() if _BIG_INLINE_ is
defined, which will probably be rare. Therefore the line
#include // to get memcpy and NULL
can be replaced with:
#ifdef _BIG_INLINE_
#include // to get memcpy
#endif
Since nearly everything includes , and since relatively few things
will want _BIG_INLINE_, this should be a winner. Note however that some code
might assume pulls in .

Borland says:
iostream.h is big and slow to compile. Other speedups are to
remove all the comments from the file. This speeds up 286
machines.

My response:
If you know iostream.h is big and slow to compile, why should you make
it approx 10% bigger and slower?

-----------------------------------------------------------------------------

Severity: non-serious bug in header file
Versions: occurs in both TC++ 1.00 and 1.01

needs but doesn't get it. Add this to :
#ifndef __IOSTREAM_H
#include
#endif

Borland Response:
This is not a bug. To quote from page 3-1 of the AT&T Release 2.0
Library Manual documentiing the iostreams package,
"The declarations for the iostream library exist in several
header files. To use any part of it, a program should include
. Other header files may be needed for other
operations."
e.g. or
-----------------------------------------------------------------------------

Severity: missing header file
Versions: occurs in both TC++ 1.00 and 1.01

There is no . I constructed the following work-alike. It should go
into your standard include directory (where is, for example):
// new.h
// Author: Dr. Marshall Cline/ECE Dept/Clarkson Univ/Potsdam,NY 13676
// Email: [email protected]
// Phone: Voice: 315-268-6511; Fax: 315-268-7600
// Copyright: The Author releases this to the Public Domain,
9-July-90.
// Date: 9-July-1990
// Please include these acknowledgements when distributing this file
#ifndef __NEW_H
#define __NEW_H
#ifndef _SIZE_T
#define _SIZE_T
typedef unsigned size_t;
#endif
void* operator new(size_t size, void* ptr);
// _new_handler is a ptr to a parameterless function returning void
extern void (*_new_handler)();
void (*set_new_handler(void (*replacement_handler)()))();
#endif __NEW_H

Borland says:
NEW.H is NOT defined by AT&T 2.0 C++ specs. The contents
were in C++ specs 1.2 and is making a comeback in the
upcoming ANSI C++ spec. We do have the underlying code, ie
_new_handler support, but it is not documented. It would be
nicer to use a typedef for the void function pointer, for the
above work-around.

-----------------------------------------------------------------------------

Severity: serious bug in iostreams
Versions: occurs in both TC++ 1.00 and 1.01

Bug in istream: an extremely common C++ main input loop is something like:
while (cin >> chunk) chunk.do_something();
This works under the condition that istream::operator void* returns 0 (false)
after the input stream reads past EOF (or encounters an error). TC++'s
iostream.h is consistent with its documentation [programmer's guide p.183] in
stating that this operator returns 0 only when istream::fail() is true (when
failbit, badbit or hardfail are set), but unfortunately `fail' doesn't get
set after you've read past EOF. The correct operation is to return 0 (false)
on the read after you've run into EOF as well [Lippman p.384], which CAN BE
accomplished by the _bad bit being set wnen seeking past end-of-file [Lippman
p.402]. This can be fixed by changing "ios::operator void*()" in
as follows:
inline _Cdecl ios::operator void* ()
{ return (state & (eofbit|failbit|badbit|hardfail)) ? 0 : this; }
NB: the `official' (if there is such a thing in these pre-ANSI-C++ days)
behavior of istream::operator>> isn't clear. I've discussed this matter with
both Borland, as Rob Murray, who is in charge of certain C++ libraries inside
AT&T, and no one is yet sure what is really ``supposed'' to happen. The
above patch (checking the eofbit) appears to work correctly, but it may be
that a more comprehensive solution is eventually in order. In any event, most
people's code doesn't run around checking individual bits inside an ios, so
the above is probably `safe'.

Borland says:
Although this code happens to work in AT&T's CFRONT
implementation of C++, there is no documentation stating how
this code should operate. To test for EOF we recommend
breaking the statement down ie ifstream joe;
while (!joe.eof())
{
joe >> ch;
}
This should be up for debate by the C++ developers.

-----------------------------------------------------------------------------

Severity: serious bug in code generator
Versions: only in TC++ 1.00; fixed in 1.01.

There is an error in TCC that isn't in TC (they generate different code).
[Borland is as surprised that they'd behave differently as I was; I'd imagine
the internals are identical, and this assumption has be confirmed by Borland].
When a virtual fn is called from a non-virtual inline member, the virtualness
of the call vanishes. Compile the following with `tcc -vi':
#include
class B {
public:
virtual void virt();
void nonvirt() { cout << "B::nonvirt() calling "; virt(); }
};
class D : public B {
public:
void virt();
};
main()
{
D d;
(&d)->nonvirt(); // B::nonvirt() should call D::virt()
d.nonvirt(); // ditto
}
void B::virt() { cout << "B::virt()\n"; }
void D::virt() { cout << "D::virt()\n"; }
Unfortunately both of these call B::nonvirt().
Ie:Both d.nonvirt() & (&d)->nonvirt() translate to "call near ptr @B@virt$qv".
Obviously these should be virtual function calls. This is a serious error, as
calling a virtual from a non-virtual is fairly common. Note: if B::virt() is
a pure virtual (another legal operation, but perhaps not as common), the call
to "@B@virt$qv" generates a linker error (there is no B::virt()!). If
B::nonvirt() is a regular (non-inline) function (either by moving it out of
the class, or by `-v' or `-vi-'), TCC generates the correct code. Strangely
enough, TC appears to *always* generate the correct code.

Borland says:
TRUE, and fixed as of version 1.01.

-----------------------------------------------------------------------------

Severity: serious illegal naming of header file
Versions: occurs in both TC++ 1.00 and 1.01

The 1.2 streams package (called ) is nice, however AT&T treats the
inclusion of as an alias to . Therefore you should
rename it from to , and let simply be:
#include
It is notable that a number of posters on comp.lang.c++ have been confused by
including thinking they were getting ...

Borland says:
TRUE, but this is a 2.0 implementation, and we have included
oldstreams as an added feature.

My response:
Including `old' streams was nice, since it will give users a chance to
compile old code. Thank you. However the header file name is
reserved, and should not be used as a method to include 1.2 streams:
``The stream.h include directive continues to be supported.
It is treated as an alias for the iostream.h header file.''
[Lippman, `C++ Primier,' A/W, 1989, p.372]

-----------------------------------------------------------------------------

Severity: non-serious incompatibility in rarely used header file
Versions: occurs in both TC++ 1.00 and 1.01
Thanks to: Pete Humphrey / [email protected] / 505-345-1863
EDS Research / 5951 Jefferson Street NE / Albuquerque, NM
87109-3432

: Instead of using the usual "name2" style macros, Borland
invented their own set of macros for concatenating pieces of names. Any code
using the Stroustrup-style macros (eg. code compatable with g++, CC, or
Zortech C++) will break. A work-around is to stick the following on the
bottom of your :
#define name2 _Paste2
#define name3 _Paste3
#define name4 _Paste4

Borland says:
TRUE. As to why . . . copyright issues.

[I hope that doesn't mean every compiler will be forced to use its own
naming scheme! M.Cline]

Borland Response:
The macros inside of generic.h are not standardized nor specified
in AT&T 2.0, so the design of the macros was left for the implementor.
-----------------------------------------------------------------------------

Severity: ??
Versions: ??
Disclaimer: I haven't reproduced this bug, and Borland wasn't able to either
Thanks to: Zerksis Umrigar/[email protected]/SUNYBinghamton
NY

TC++ signals a compiler error when the LAST default parameter for a
constructor
is initialized by a constructor for some other class. A workaround is to add
an extra dummy default parameter of some predefined type like int. Ex: if A
and B are classes, then:

This will be an error: A::A(B b = B(...));
But this is ok: A::A(B b = B(...), int dummy=0);

Borland says:
Could not reproduce.

Response:
Please let me know if anyone else can reproduce this. If it was a fluke in
the particular program (or a wild pointer that trashed the code), I would
like to remove this entry from the list PRONTO. Thanks. M.Cline.

-----------------------------------------------------------------------------

Severity: serious bug in code generator
Versions: occurs in TC++ 1.00; Borland says it's fixed in 1.01
Thanks to: Jamshid Afshar/[email protected]

When an object is created as a side effect of an expression, and the
expression
is short-circuited, the destructor for the object seems to get called anyway.
Ex: compile this with `tcc -vi-':
extern "C" int rand();
#include
class X {
int xyz;
int pqr;
public:
X create_copy_of_X() { return *this; } //Return *BY VALUE*
X();
X(const X&);
int whatever();
~X();
};
void f();
void g();
main()
{
X x;
if (rand()==0 && x.create_copy_of_X().whatever()) f(); else g();
}
void f() { cout << "yes\n"; }
void g() { cout << "no\n"; }
X::X() : xyz(rand()), pqr(rand())
{ cout << "constructing an X at " << ((void*)this) << "\n"; }
X::~X() { cout << "destructing an X at " << ((void*)this) << "\n"; }
X::X(const X& x) : xyz(x.xyz), pqr(x.pqr)
{ cout << "copying an X from " << ((void*)&x) <<
" to " << ((void*)this) << "\n"; }
X::whatever() { return rand(); }
At the close of main() (in fact, before `f()' is even called), TC++ calls a
destructor on the copy of `x' even though the copy was never constructed.

Borland says:
True. Fixed in v1.01

-----------------------------------------------------------------------------

Severity: serious bug in code generator
Versions: occurs in both TC++ 1.00 and 1.01

An explicit 2-parameter ctor in a by-value return statement is sometimes very
useful in practice. Ex: a string concatenation operation, as it is typically
implemented, uses much too much CPU; ex:
class String {
char* data;
int len;
friend String operator+(const String& A, const String& B);
public:
String(const char*);
//...
};
String operator+(const String& A, const String& B)
{
/*line-1*/ char* mem = new char[A.len + B.len + 1];
/*line-2*/ strcpy(mem, A.data);
/*line-3*/ strcat(mem, B.data);
/*line-4*/ String ans = mem;
/*line-5*/ delete mem;
/*line-6*/ return ans;
} /*line-7*/
Couting freestore operations: line 1 uses a `new', line 4 uses a `new', line
5 uses a `delete', line uses string's copy ctor which uses another `new', and
line 7 `delete's the temporary string `ans'. Final score: 3 new, 2 delete's.
A smart compiler will construct `ans' in the location of the return value,
which will reduce this to 2 new's and 1 delete. But a simple strategy can
reduce it even further to 1 `new' and zero (0) delete's (even if the compiler
isn't very smart):
class String {
char* data;
int len;
friend String operator+(const String& A, const String& B);
String(char* _data, int _len) : data(_data), len(_len) { }
public:
String(const char*);
//...
};
String operator+(const String& A, const String& B)
{
/*line-1*/ char* mem = new char[A.len + B.len + 1];
/*line-2*/ strcpy(mem, A.data);
/*line-3*/ strcat(mem, B.data);
/*line-4*/ return String(mem, A.len + B.len);
} /*line-5*/
The private constructor String::String(char*,int) is what I call a `trust-me'
ctor. Ie: it is only usable by trusted routines, which I enforced by making
it private. It just creates a String by copying the *pointer* & the length.
The pointer is *assumed* to be a pointer allocated by `new char[...]', since
``String::~String()'' will `delete' the pointer. Furthermore the `length' is
assumed to be correct. Final score: there's only ONE `new' in operator+ (on
line 1) and ZERO `delete' operations. There are no dangling pointers, and no
memory `leaks'. Ok, now to TC++'s problem:
Line 4 [[``return String(mem, A.len + B.len);'']] is interpreted by TC++ to
mean ``construct the return value right on the stack'' (ie: not a temporary
object, but the actual return location). TC++ does the right thing by not
creating a temporary, otherwise it would have to copy to the return location
and then `destruct' the temporary. HOWEVER, TC++ then goes ahead an treats
the constructed object as if it *were* a temporary, and it tries to copy it
to the return location, which is where it already is! Thus the copy ctor is
called with `this' pointing to *itself*. This is disasterous if copy ctor
allocates memory; Ex:
String::String(const String& S)
{
data = new char[S.len+1]; //If &S == this, changes S.data
also!!
strcpy(data, S.data); //Copy GARBAGE into itself
len = S.len;
}
WORKAROUNDS: [1] If there's a one-parameter ctor that will automatically
convert to the return value, then you don't need an explicit constructor in
the return stmt. [2] If you need a more-than-one parameter ctor (ex:
``return complex(re,im)'', then you can construct a temporary and return the
temporary by value. For example:
complex foo()
{ //...
complex my_return_value = complex(re, im);
return my_return_value;
}
Unfortunately this won't be as fast since it requires an extra copy ctor
and the temporary (``my_return_value'') has to be `destructed'.

Borland's Response:
We replicated the problem, and it should be fixed in a future version.

-----------------------------------------------------------------------------

Severity: non-serious missed feature
Versions: occurs in both TC++ 1.00 and 1.01

Missed Feature: There is a subtle C++ bug in the code below. Even though the
initialization list in String::String(const char*) looks like Len will get
initialized before s, in fact the initialization order is fixed by the
position
within the class, which is just the opposite. Thus an arbitrary and
unpredictable amount of storage will be allocated! (I put this `missed
feature' in the `bug' report because TC++ users are used to TC++'s *excellent*
warnings, and they may be puzzled if the compiler silently accepts code which
is patently wrong. For example, TC++ complains about locals that are used
before they're initialized, and this is an analogous situation.)
class String {
char* s;
unsigned Len;
public:
String(const char* p); // char* --> String
//...
};
String::String(const char* p) : Len(strlen(p)), s(new char[Len+1])
{ /////// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
strcpy(s, p); /////// Missed feature: TC++ should warn
here
} /////// Ex: `Len used before it is
initialized'

Borland's Response:
This is true. We have forwarded the suggestion to the developers
for their consideration.
-----------------------------------------------------------------------------

Severity: ??
Versions: ??
Disclaimer: I haven't personally checked this -- MPC
Thanks to: Joseph Puglielli, Santa Barbara, CA

The #if/#else/#endif bracketed pair that follows should be functionally
equivalent, but they're not:

#include
#include
void error(const char*);
#if 1
class Reader {
ifstream input;
char data[100];
public:
Reader(const char* fname)
{ if (!input.open(fname, ios::nocreate | ios::binary))
error("can't open file in Reader::Reader(const char*)");
}
~Reader(const char* fname) { input.close(); }
void getin()
{ memset(data, '\0', 100);
if (!input) error("Reader::getin() -- input file is trashed");
for (int i = 0; i < 100 && !input.eof(); ++i)
{ char c; input.get(c); data[i] = c; }
}
};
main() { Reader r("input.txt"); r.getin(); }
#else
main()
{
ifstream input;
char data[100];
char* fname = "input.txt";
if (!input.open(fname, ios::nocreate|ios::binary)) error("can't open file");
memset(data, '\0', 100);
if (!input) error("main() -- input file is trashed");
for (int i = 0; i < 100 && !input.eof(); ++i)
{ char c; input.get(c); data[i] = c; }
input.close();
}
#endif

Borland's Response:
First, the program, as written, has two syntax errors in it. The
fstream function 'open' has no return value, thus it's usage in the
'if' statements occuring in both sections of the program is illegal.
The correction is something like:

...
input.open(fname, ios::nocreate | ios::binary);
if(!input)
...

As far as the functionality of the program, true. The developers are
aware of a problem with declaring an instance of an ifstream in a class.
It should be fixed in a future version.

-----------------------------------------------------------------------------

Severity: ??
Versions: ??
Disclaimer: I haven't personally checked this -- MPC
Thanks to: Joseph Puglielli, Santa Barbara, CA

The following two `x's shouldn't conflict, since `x' is a local `type'
in each class. However they do conflict.

class A { enum x { zero, one, two }; };
class B { enum x { apple, orange, pear }; };

Borland's Response:
According to the AT&T 2.0 Reference Manual 7.2 "the name of the
enumeration itself is not local to the class." In the above code,
x is not local to either class, so it should be flagged as conflicting.

-----------------------------------------------------------------------------

Severity: ??
Versions: ??
Disclaimer: I haven't personally checked this -- MPC
Thanks to: Scott Schram / 72561,207 on compuserve / sshram on BIX:

When you compile with -N (stack checking ON), TC++ declares _stklen at the
first function definition (when it emits code to do the stack-overflow check).
The only way you can use it to extend the stack is to include *BEFORE*
your first function definition. Ex: this will fail:
int a(void) { return 0; } // Implicitly causes _stklen to be declared
unsigned _stklen = 20000; // This *RE*-declares _stklen...
main() { a(); return 0; }
Instead use this:
#include // EXPLICITLY declares _stklen
int a(void) { return 0; } // Implicitly causes _stklen to be declared
unsigned _stklen = 20000;
main() { a(); return 0; }

Borland's Response:
This is true. The dos.h file is required, just as other header files
are necessary for things like printf(). Be sure to specify
extern unsigned _stklen = (somevalue);
as described in the Turbo C++ Reference Guide and helpme!.doc file.

-----------------------------------------------------------------------------

Severity: non-serious missed optimization
Versions: ??
Disclaimer: I haven't personally checked this -- MPC
Thanks to: Kevin Routley - Digital Equipment Corp, [email protected]

BITFIELD OPERATION PERFORMANCE

Bitfield operations are not optimal. See Example 1 for an example program.
Testing the first bit of a multi-bit bitfield structure is done in 20 (8086)
cycles with the TEST instruction:
TEST WORD PTR [BP-06], 0001
The third bit in a multi-bit bitfield structure is testing by performing a
pair of shift instructions, requiring 25 cycles:
MOV AX, WORD PTR [BP-06]
SHR AX, 1
SHR AX, 1
TEST AX, 0001
Larger bitfield structures use the multiple shift instruction to test higher
bits. For example, the eighth bit requires seven shifts and 61 cycles to test:
MOV AX, WORD PTR [BP-06]
MOV CL, 7
SHR AX, CL
TEST AX, 0001
This poor optimization places severe penalties on those programs that might
choose to use bitfields to store flags instead of char objects. As far as
space is concerned, it is more efficient to use a bitfield structure for three
or more boolean flags rather than chars. The bitwise & operator illustrates
that all three tests above could have been performed with individ- ual TEST
instructions (a total of 63 cycles compared to the 106 cycles required by the
above tests):
TEST WORD PTR [BP-06], 0001
TEST WORD PTR [BP-06], 0004
TEST WORD PTR [BP-06], 0080
In fact, a series of similar (& or |) operations on bitfield structure
elements could be optimized to a single TEST instruction.

EXAMPLE BITFIELD PROGRAM:
#include
main()
{
struct foo
{
unsigned flag1 : 1;
unsigned flag2 : 1;
unsigned flag3 : 1;
unsigned flag4 : 1;
unsigned flag5 : 1;
unsigned flag6 : 1;
unsigned flag7 : 1;
unsigned flag8 : 1;
} flags;
char lflag1 = 0;
char lflag2 = 1;
char lflag3 = 0;
char lflag4 = 1;
flags.flag1 = flags.flag8 = 1;
if ( flags.flag1 && flags.flag8 && lflag2 && lflag4 )
printf("True\n");
else
printf("False\n");
}

Borland's Response:
This is true. We have passed this to the developers for consideration.
Thanks for the suggestion.

-----------------------------------------------------------------------------

Severity: limitation of the preprocessor
Versions: ??
Disclaimer: I haven't personally checked this -- MPC
Thanks to: Kevin Routley - Digital Equipment Corp, [email protected]

MACRO EXPANSION LIMIT

The limitation of 4096 characters for a macro expansion is too small for
non-toy programs. This can prevent Turbo C++ from being used as a development
environment for large programs. Ideally a macro expansion should only be
limited by the compiling machine's memory (if that, using memory swapping).

As an example, multiple data structures can be easily and conveniently
initialized from a single instance of the entered information (illustrated in
Example 2. If table_data contains more than a few lines with more than a
couple of items, and the author uses spaces to insure readibility, you can
easily exceed the 4096 character limit.

EXAMPLE: STRUCT INIT. FROM A SINGLE SET OF DATA
/* setup the data to init all the structures with */
#define table_data \
X( "text1", 0, CONST1, 1, 1, 0, struct1, 1 ) \
X( "text1234", 0, CONST1234, 1, 1, 0, struct2, 1 ) \
. . . \
X( "text99", 0, CONST99, 0, 0, 0, structure99, 0 )

/* setup the macro to init table1. Only some of the fields are used.*/
#define X (string, foo, bar, fum, foobar, dataptr, flag )\
{ foo, bar, fum, flag }
/* table1 is an array of structs, each with four int fields*/
table1[MAX_TABLE] = { table_data };
#undef X

/* setup a different macro to init table2. */
/* Different fields are used this time. */
#define X (string, foo, bar, fum, foobar, dataptr, flag )\
{ flag, string }
table2[MAX_TABLE] = { table_data };
#undef X

Borland's Response:
Thank you for the suggestion to increase the maximum characters in
macro expansion. The suggestion has been passed to the developers.

-----------------------------------------------------------------------------

Severity: non-serious missed feature in integrated environment
Versions: ??
Disclaimer: I haven't personally checked this -- MPC
Thanks to: Kevin Routley - Digital Equipment Corp, [email protected]

TC.EXE DISPLAY CUSTOMIZATION

I am unable to customize the colors of the integrated environment so that they
display reasonably on my monochrome VGA monitor. TCINST has an option "Mode
for Display". No matter which option I select (e.g. Black and White, or
Monochrome) to customize TC.EXE to have, I always get the same default color
display mode when I invoke TC.EXE. The default mode is very difficult to read
on my monochrome display.

Borland's Response:
True. The developers are aware of this.

-----------------------------------------------------------------------------

Severity: non-serious error in support tool
Versions: occurs in both TC++ 1.00 and 1.01
Disclaimer: I haven't personally checked this -- MPC
Thanks to: Mark (M.S.) Lord :

The GREP utility doesn't correctly display its permanent option settings.
Ex: turn on the UNIX-style option and then display the options.
The problem should be immediately obvious.

You can patch the GREP.EXE by locating the table of screen offsets used
internally for this purpose.

Borland's Response:
True. The parameters that do not update correctly are -o+, -u+,
and -w+. We have made a report to the developers.
-----------------------------------------------------------------------------

Severity: serious bug inside stream and/or fstream classes
Versions: ??
Disclaimer: I haven't personally checked this -- MPC
Thanks to: James J. Hartley / Dept CS / Univ of Missouri-Rolla

[email protected]/[email protected]@umrvmb.bitnet/...!uunet!cs.umr.edu!jamesh

//The following code represents the bug in its simplest form:
#include
#include
#include
class persist {
char *fname;
protected:
fstream dskfile; // file stream declared in base class
public:
persist(char *fn) {
fname = new char [strlen(fn) + 1];
strcpy(fname, fn);
dskfile.open(fname, ios::in | ios::out);
if (!dskfile) { cerr << "error in opening "< }
~persist() { dskfile.close(); delete fname; }
};
class constant : public persist {
unsigned int k;
public:
constant(char *fn) : persist(fn) { dskfile >> k; } // I/O in
derived class
unsigned int get_constant() { return k; }
};
main() {
constant k("CONSTANT.TXT");
cout << "k = " << k.get_constant() << "\n"; // gives flaky
results
return 0;
}

As you can see, I am declaring a file stream instantiation in a base class and
perform input in a derived class. Unpredictable values are displayed from
both the integrated development environment and from the command-line.

In talking to Lori in Technical Support at Borland, problems with declaring
streams within classes have been reported before and is currently on their bug
database. I found streams can be declared and used correctly within the scope
of a member function (constructor). This can be seen in the following code:

#include
#include
#include
class constant {
unsigned int k;
char *fname;
public:
constant(char *fn) { // moves the stream to the constructor's scope
fname = new char[strlen(fn) + 1];
strcpy(fname, fn);
fstream dskfile(fname, ios::in | ios::out);
dskfile >> k;
dskfile.close();
}
unsigned int get_constant() { return k; }
~constant() { delete fname; }
};
main() {
constant k("CONSTANT.TXT");
cout << "k = " << k.get_constant() << "\n"; // output is correct!
return 0;
}

The obvious workaround is to revert to the file I/O conventions used in C
(fopen() & fclose()). In simulating persistent objects, I have used this
method and have gotten consistent results.

Borland's Response:
Same problem with fstreams mentioned above.

-----------------------------------------------------------------------------

PS: If your company is interested in on-site C++/OOD training, drop me a line!
PPS: Career search in progress; ECE faculty; research oriented; will send
vita.
--
Marshall Cline / Asst.Prof / ECE Dept / Clarkson Univ / Potsdam, NY 13676
[email protected] / Bitnet:BH0W@CLUTX / uunet!clutx.clarkson.edu!bh0w
Voice: 315-268-3868 / Secretary: 315-268-6511 / FAX: 315-268-7600


  3 Responses to “Category : C Source Code
Archive   : TCPBUGS2.ZIP
Filename : BUGS.TXT

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/