Path: utzoo!attcan!uunet!cs.utexas.edu!uwm.edu!ogicse!ncube.com!oracle!news From: jeras@oracle.oracle.com (John Eras) Newsgroups: comp.sys.ibm.pc.programmer Subject: Re: Bug in TC2.0 Summary: NOPE! Not a bug... Message-ID: <1990Jun3.225832.25725@oracle.com> Date: 3 Jun 90 22:58:32 GMT References: Reply-To: jeras@oracle.com (John Eras) Distribution: comp.sys.ibm.pc.programmer Organization: Oracle Corporation, Belmont, CA Lines: 76 In article 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."