[comp.sys.ibm.pc.programmer] Bug in TC2.0

rfrost@spam.ua.oz.au (Richard Frost) (06/03/90)

I have found what I think is a bug in version 2.0 of the Turbo C compiler.

I am a K&R C programmer from some time back and have not read the full specs
on ANSI C so I may be wrong.

Bug Description:
================

Consider 2 separately compiled C modules "A.c" and "B.c" which share an
array which is altered by a function in "B.c".

The 2 modules look like:

A.c:					B.c:
====					====

extern void testfn(void);

char Test[] = {0xB0,0xB0,0xB0};		extern char *Test;

main(int argc, char *argv[])		void testfn(void)
{					{
 ...					 ...
 testfn();
			 	 	 Test[1]  = 'A';
			 		 *(Test+2) = 'B';

}					}

When testfn() is called in main() it returns without altering
the array Test, however if the external reference to the array
in B.c is written as "extern char Test[]" then the function
succeeds in altering the array Test.

After looking at the assembly code produced, if the orignal external
reference is used when the code "Test[1]='A';" is executed, TC produces
code which dereferences Test as though it is a pointer to 
a pointer to char thus giving the address 0xB0B0 (which are the chars
in the initialized array) and then adding 1 and assigning to that address.

(Note: incorrect code is also produced for the other array access :
  *(Test+1) = 'B'; )

Correct assembly is produced when the other external reference is used,
ie "extern char Test[];" when the array is accessed in both manners shown.

I would like to know if this is really a bug, I think it IS according to K&R
rules.

Has anyone else had similar problems?.

--
______________________________________________________________________________
_          ___       | Email Address:  rfrost@spam.ua.oz.au
I)         I_        |
I\ ichard  I rost    | FidoNet (ADAM LINK BBS): 3:680/805 Richard Frost
---------------------+--------------------------------------------------------
Bewildered Earth Scientist: "How do you re-wire alien equipment like that??"
Dr. Who: "Its easy when you've had 900 years experience in alien technology."
______________________________________________________________________________

jeras@oracle.oracle.com (John Eras) (06/04/90)

In article <RFROST.90Jun3234439@spam.ua.oz.au> rfrost@spam.ua.oz.au (Richard Frost) writes:
>
>I have found what I think is a bug in version 2.0 of the Turbo C compiler.
>
>I am a K&R C programmer from some time back and have not read the full specs
>on ANSI C so I may be wrong.

I don't think it is a bug, but I can understand the confusion.  I have had
problems very similar (identical, in fact!) in my coding experience with 
MSC 5.1.  On the surface it looks like it could be a bug, but I think if
you think about it for a little while you will see otherwise...

>Bug Description:
>================
>
>Consider 2 separately compiled C modules "A.c" and "B.c" which share an
>array which is altered by a function in "B.c".
>
>The 2 modules look like:
>
>A.c:					B.c:
>====					====
>
>extern void testfn(void);
>
>char Test[] = {0xB0,0xB0,0xB0};		extern char *Test;
>
>main(int argc, char *argv[])		void testfn(void)
>{					{
> ...					 ...
> testfn();
>			 	 	 Test[1]  = 'A';
>			 		 *(Test+2) = 'B';
>
>}					}
>
>When testfn() is called in main() it returns without altering
>the array Test, however if the external reference to the array
>in B.c is written as "extern char Test[]" then the function
>succeeds in altering the array Test.
>
>After looking at the assembly code produced, if the orignal external
>reference is used when the code "Test[1]='A';" is executed, TC produces
>code which dereferences Test as though it is a pointer to 
>a pointer to char thus giving the address 0xB0B0 (which are the chars
>in the initialized array) and then adding 1 and assigning to that address.

Okay, think about what is happening here.  "Test" is an array of characters
in module A, but in module B you have declared it as a pointer to an array
of characters.  I think the confusion is coming from this:  we all know 
that if you use the name of an array (in this case "Test"), then that is
taken to be a pointer to the first element in that array (or &Test[0]).  
However, this is only if you have declared it as an array in the first 
place (as in module A).  When you declare it as a pointer to an array of 
characters (that's what a char * is, of course) in module B, then the 
compiler thinks it has to load the pointer at the address in question 
(which is really * (&Test[0]) or Test[0] or 0xB0B0 in this case -- I 
assume you're using small data model).  When you declare Test correctly as 
"char Test[]" in module B, then the compiler knows what's going on, and the 
correct code results.

I hope this makes sense.  As I said before, I get confused about this at
times, too, but it usually will make sense to me after I put my thinking 
cap on and think about it a little while.

Note that clever use of the preprocessor can avoid problems like this.  In
other words, declare and define the global variable in one and only one file
(a header file), using #ifdef's to conditionally determine whether the 
variable is to be defined/initialized (as in module A) or just declared (as
in module B).  I'll leave the implementation of this as an exercise for 
the reader.

----------------------- (: smile! you're on usenet! :) ------------------------
AT:    jeras@oracle.com                              | "It's a terrible waste
BANG:  ...{pacbell,hplabs,apple,decwrl}!oracle!jeras | to lose one's .sig, or
FLAME: /dev/null (nyuk, nyuk)                        | not to have one at all."

torkil@psivax.UUCP (Torkil Hammer) (06/05/90)

In article <RFROST.90Jun3234439@spam.ua.oz.au> rfrost@spam.ua.oz.au (Richard Frost) writes:
# 
# I have found what I think is a bug in version 2.0 of the Turbo C compiler.
# 
..

# char Test[] = {0xB0,0xB0,0xB0};		extern char *Test;
# 
# main(int argc, char *argv[])		void testfn(void)
# {					{
#  ...					 ...
#  testfn();
# 			 	 	 Test[1]  = 'A';
# 			 		 *(Test+2) = 'B';
# 
# }					}

No, not a bug in the compiler.  A bug in your code, in K&R as well as
ANSI standard.  A pointer is not the same as an array.  The code on
the right could work if you declared a global pointer named Test and
initialized it in the main program to point at the start of the global
array Test before calling testfn.

On a second thought, I think you will have to give the pointer a different
name from Test, but then it should work as desired.