cml@giza.cis.ohio-state.edu (Christopher Lott) (08/11/89)
Hi, I am asking about the scope and declaration of a variable; I have read K&Rv2, p. 227-228, Scope and Linkage, but can't seem to dig out the answer. (what is a 'translation unit' ??) In the 2 files below, a variable ("twice") is declared, and has space allocated for it (i think) in both files. However, the linker does not complain about a multiply-defined symbol, and the program works just as if one of the symbols had been prefixed by an "extern" keyword. As far as I can tell, what I am doing below is incorrect, but would like to know what is happening to make it appear to work correctly. /* text from one.c */ int twice; main() { twice = 23; printf("value of twice is %d\n", twice); printf("calling function two.\n"); two(); printf("value of twice is %d\n", twice); printf ("all done.\n"); return(0); } /* text from two.c */ int twice; /* <- not declared extern */ int two() { printf("value of twice is %d\n", twice); printf("resetting twice\n"); twice = 83; return(0); } To test this, put the following program text into two files (one.c & two.c), then type "cc -o one one.c two.c". No makefile, sorry. This question cropped up when I noticed that an object was being declared in a header file ("int j;") and that header file was included by many files. If the answer is just painfully obvious :-), please email, and I'll repost. Thanks in advance! chris... -=- cml@cis.ohio-state.edu Computer Science Dept, OSU 614-292-1826 or: ...!{att,pyramid,killer}!osu-cis!cml <standard disclaimers>
gwyn@smoke.BRL.MIL (Doug Gwyn) (08/11/89)
In article <57257@tut.cis.ohio-state.edu> Christopher Lott <cml@cis.ohio-state.edu> writes: >(what is a 'translation unit' ??) A source file and the other files it #includes, directly or indirectly. >... However, the linker does not complain about a multiply-defined symbol, ... Yes, that's because your C implementation uses the "COMMON" model for external object linkage, instead of the "DEF/REF" model described in K&R (1st Edition). Most UNIX systems are that way. For portability, you should fix the source so that there is only one non-"extern" declaration of such an object among all the translation units that produce the object modules that get linked together.
cpcahil@virtech.UUCP (Conor P. Cahill) (08/11/89)
In article <57257@tut.cis.ohio-state.edu>, cml@giza.cis.ohio-state.edu (Christopher Lott) writes: > > I am asking about the scope and declaration of a variable; I have > read K&Rv2, p. 227-228, Scope and Linkage, but can't seem to dig out > the answer. (what is a 'translation unit' ??) > 1. I believe a translation unit is a .c file. 2. Definitions of global data elements: real definition: a declaration with an initialization tentative definition: a declaration without an initialization A global symbol may have unlimited tentative definitions, but only 1 real definition. In other words, you can have "int i;" in every .c and they will all refer to the same data space. You can even have "int i=3;" in one (but only one) of the source files and they will still refer to the same data space. But if you have more than one "int i=2;", even if you set the initial value to the same value, the loader (ld) will complain about multipley defined symbols.
karl@haddock.ima.isc.com (Karl Heuer) (08/12/89)
In article <1001@virtech.UUCP> cpcahil@virtech.UUCP (Conor P. Cahill) writes: >[Stuff about real vs. tentative definitions] A global symbol may have >unlimited tentative definitions, but only 1 real definition. I think you're confusing tentative definitions with non-defining declarations. >In other words, you can have "int i;" in every .c and they will all refer to >the same data space. This is not correct. A tentative definition retroactively becomes a real definition if the end of the source file is reached without seeing a real definition. The purpose of the tentative-definition nonsense is not to force the Common-block storage model to work; it's to allow forward reference to non-global identifiers. Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
cpcahil@virtech.UUCP (Conor P. Cahill) (08/12/89)
In article <14270@haddock.ima.isc.com>, karl@haddock.ima.isc.com (Karl Heuer) writes: > In article <1001@virtech.UUCP> cpcahil@virtech.UUCP (Conor P. Cahill) writes: > >[Stuff about real vs. tentative definitions] A global symbol may have > >unlimited tentative definitions, but only 1 real definition. > > I think you're confusing tentative definitions with non-defining declarations. I am not. > > >In other words, you can have "int i;" in every .c and they will all refer to > >the same data space. > > This is not correct. A tentative definition retroactively becomes a real > definition if the end of the source file is reached without seeing a real > definition. The purpose of the tentative-definition nonsense is not to force > the Common-block storage model to work; it's to allow forward reference to > non-global identifiers. > A tentative definition of a data object is not resolved at the end of source module, but at link time. I quote from K&R2 pg 227, ...In the alternate formulation, which is usual in UNIX systems and recognized as a common extension by the Standard, all tentative definitions for an externally linked object, throughout ALL the translation units of a program are cosidered together instead of in each translation unit separately. If a definition occurs somewhere in the program, then the tentative definitions become merely declarations, but if no definition appears, then all its tentative definitions become a definition with initializer 0. "tentative definition" is defined as "an external object declaration that does not have an initializer, and does not contain the extern specifier" Therefore what I said is absolutely correct. BTW, I don't see how any of this applies to a "forward reference to non-global identifiers".
gwyn@smoke.BRL.MIL (Doug Gwyn) (08/12/89)
In article <1002@virtech.UUCP> cpcahil@virtech.UUCP (Conor P. Cahill) writes: > ...In the alternate formulation, which is usual in UNIX systems and > recognized as a common extension by the Standard, ... However, note that this "common extension" (so-called because that is the title of the section of the Standard wherein it is described) violates the requirements of the Standard. The "common extensions" are not in the enforceable part of the Standard, and some of us think they have no business being printed as an apparent part of the Standard. (We were outvoted, though; the "Common Extensions" section had political if not technical value.) int i; at file scope (assuming there is no other file-scope definition for i in the same translation unit) does reserve storage for i, and it does have the initial value 0. A standard-conforming translator is obliged to enforce this. Since it also has external linkage, the occurrence of int i = 17; at file scope in another translation unit directly conflicts with the 0 initializer of the first translation unit. These rules date back to the first edition of K&R.
karl@haddock.ima.isc.com (Karl Heuer) (08/14/89)
In article <1002@virtech.UUCP> cpcahil@virtech.UUCP (Conor P. Cahill) writes: >A tentative definition of a data object is not resolved at the end of source >module, but at link time. I quote from K&R2 pg 227 ... As Doug mentioned, this is a Common Extension, not guaranteed to work on all conforming implementations. >BTW, I don't see how any of this applies to a "forward reference to >non-global identifiers". Consider a source file that contains static int x; int f() { return x; } static int x = 3; The third line is the real definition of x; the second line contains a forward reference to it, which is enabled by the tentative definition on the first line. In pre-ANSI C, this was not legal because "static int x;" was a real definition with implied initializer zero (at least in some linkage models). Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint