zhoumi@nff.ncl.omron.co.jp (Zhou Mi) (05/20/91)
When I am working in a project, I find that someone in my group write the following program. Though it seems work well, I still wonder if it is correct or better ?? -----file 1 (named pro_all.h) --------- int i; ------file 2 (named pro_main.c) -------- #include "pro_all.h" void main() { sub1(); sub2(); sub3(); } --------- file 3 (named pro_sub1.c) -------- #include "pro_all.h" void sub1() { i = 1; } --------- file 4 (named pro_sub2.c) --------- #include "pro_all.h" void sub2() { i++; } --------- file 5 (named pro_sub3.c) --------- #include "pro_all.h" void sub3() { i += 3; } If anyone has the result, please mail to me. my E-mail address is: zhoumi@nff.ncl.omron.co.jp -- +------ From: Zhou Mi ||=======||{}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{} ||\ / ||{} Zhou Mi, RZE, Systems R&D LAB., OMRON Co. {} || \ / ||{} E-mail: zhoumi@nff.ncl.omron.co.jp {} || \/ ||{} TEL: 075-951-5111 x 3176 {} || /\ ||{}=============================================================={} || / ||{} What is AI ? This is the very question that AI machine can {} ||/ ||{} answer, but one can not !! {} ||=======||{}______________________________________________________________{}
mikegord@generic.UUCP (Mike Gorodnitzky) (05/21/91)
There seems to be one problem that may prevent compiling, or rather, linking. The problem is that because the variable 'i' is declared in several modules (4),the linker will choke as it is illegal to do this. It will have global's called'i' conflicting with each other. This is bad. What you may want to do is declare in: pro_all.h--------- extern int i; pro_main.c-------- int i; And keep the rest as is. I haven't actually tried this, so can't be 100% sure about it, but it should work ok.
harry@spitws111.uk.sun.com (Harry Protoolis) (05/21/91)
In article <ZHOUMI.91May20182038@marlboro.nff.ncl.omron.co.jp>, zhoumi@nff.ncl.omron.co.jp (Zhou Mi) writes: |> |> When I am working in a project, I find that someone in my group write |> the following program. Though it seems work well, I still wonder if it |> is correct or better ?? |> |> -----file 1 (named pro_all.h) --------- |> int i; |> more stuff where this is included into many .c files and used ... This is not correct, you do not say what machine/OS you are using, but on many systems (most ?) this practice would generate a linker error (multiple definition of symbol i). Maybe a standard lawyer out there can tell me what ANSI says on this one. Anyway, if it is intended that i be a global variable it should be declared in the interface file (.h) as 'extern int i', and defined in one of the .c files as int i. This will generate one instance of the variable (in the implementation (.c) file containing the definition), which will be shared by the whole program (i.e a global variable). In general .h files should only contain declarations (i.e things like typedef and extern). 'int i' is a definition and therefore belongs in an implementation file (.c). I am suprised it works at all and it is certainly not portable, or good style. What machine/OS/Compiler are you using ???? Hope this helps, Harry -- 'When I give food to the poor they call me a saint. When I ask why the poor have no food they call me a communist.' - Dom Helder Camara
grogers@convex.com (Geoffrey Rogers) (05/21/91)
In article <ZHOUMI.91May20182038@marlboro.nff.ncl.omron.co.jp> zhoumi@nff.ncl.omron.co.jp (Zhou Mi) writes: > >When I am working in a project, I find that someone in my group write >the following program. Though it seems work well, I still wonder if it >is correct or better ?? > >-----file 1 (named pro_all.h) --------- > int i; > >------file 2 (named pro_main.c) -------- > #include "pro_all.h" > > void main() > { > sub1(); > sub2(); > sub3(); > } > >--------- file 3 (named pro_sub1.c) -------- > #include "pro_all.h" > void sub1() > { > i = 1; > } > In non-ANSI C compiler/loader environments this may or may not work. You could get multiple defined symbols for i, depending upon the model that the compiler used for external variables. The above code in not ANSI conforming, because you do have multiple definitions of i. One of the ways that I got around this problem of only having one file with all of my externals is to do the following: -------------- file 1 (pro_all.h) ---------------------- #ifndef EXTERN #define EXTERN extern #endif EXTERN int i; ------------- file 2 (pro_main.c) ---------------------- #define EXTERN #include "pro_all.h" void main() { sub1(); sub2(); sub3(); } --------- file 3 (pro_sub1.c) -------- #include "pro_all.h" void sub1() { i = 1; } This way when pro_all.h is included in the main all the externals get defined and when it gets included in other files they get declared. +------------------------------------+---------------------------------+ | Geoffrey C. Rogers | "Whose brain did you get?" | | grogers@convex.com | "Abbie Normal!" | | {sun,uunet,uiucdcs}!convex!grogers | | +------------------------------------+---------------------------------+
grimlok@hubcap.clemson.edu (Mike Percy) (05/22/91)
grogers@convex.com (Geoffrey Rogers) writes: >In article <ZHOUMI.91May20182038@marlboro.nff.ncl.omron.co.jp> zhoumi@nff.ncl.omron.co.jp (Zhou Mi) writes: >> >One of the ways that I got around this problem of only having one file >with all of my externals is to do the following: >-------------- file 1 (pro_all.h) ---------------------- >#ifndef EXTERN >#define EXTERN extern >#endif >EXTERN int i; >------------- file 2 (pro_main.c) ---------------------- >#define EXTERN >#include "pro_all.h" >void main() >{ > sub1(); > sub2(); > sub3(); >} >--------- file 3 (pro_sub1.c) -------- >#include "pro_all.h" >void sub1() >{ > i = 1; >} I've seen people do this kind of thing a lot, but I've never liked having to remeber to put #define EXTERN or some such in my code. I've found it easiest to confine my global data to two files: globals.h extern int foo; extern double bar; /* and so on, declaring all global variables */ and globals.c int foo; double bar; /* rest of the definitions */ Since I've started doing this, I've not had any problems related to global data. One problem is on certain segmented machines, in certain compilers memory models, I take a hit because of the segment placement. Comments? "I don't know about your brain, but mine is really...bossy." Mike Percy grimlok@hubcap.clemson.edu ISD, Clemson University mspercy@clemson.BITNET (803)656-3780 mspercy@clemson.clemson.edu
mccrady@torolab6.vnet.ibm.com ("++Don;") (05/22/91)
> From: grimlok@hubcap.clemson.edu (Mike Percy) > > ... I've never liked > having to remeber to put #define EXTERN or some such in my code. I've > found it easiest to confine my global data to two files: > globals.h > extern int foo; > extern double bar; > /* and so on, declaring all global variables */ > > and > globals.c > int foo; > double bar; > /* rest of the definitions */ > > Since I've started doing this, I've not had any problems related to > global data. One problem is on certain segmented machines, in certain > compilers memory models, I take a hit because of the segment > placement. > > Comments? Splitting the declarations off from the definitions of variables introduced the possibility of nasty pitfalls, where somebody decides to change the type in the .h file, and forgets to change it in the .c file. Example: ----- globals.h ------------ extern int foo; extern double bar; ---------------------------- ------ globals.c ----------- short foo; float bar; ---------------------------- Some linkers won't catch this, and any stores into foo or bar will probably whomp some other data. I prefer the EXTERN approach which you seem to dread, because it lets you DEFINE and DECLARE objects at the same time. ------ globals.h ----------- #ifdef MAIN #define EXTERN #define INIT(x) = x #else #define EXTERN extern #define INIT(x) #endif EXTERN int foo INIT(5); EXTERN double bar INIT(3.14); ---------------------------- ------ globals.c ----------- #define MAIN #include "globals.h" ---------------------------- ++Don;
mjf@mjm.mjm.com (Mark Fresolone) (05/22/91)
> grimlok@hubcap.clemson.edu (Mike Percy) >grogers@convex.com (Geoffrey Rogers) writes: >>In article <ZHOUMI.91May20182038@marlboro.nff.ncl.omron.co.jp> zhoumi@nff.ncl.omron.co.jp (Zhou Mi) writes: >>> >>One of the ways that I got around this problem of only having one file >>with all of my externals is to do the following: >>-------------- file 1 (pro_all.h) ---------------------- >>#ifndef EXTERN >>#define EXTERN extern >>#endif >>EXTERN int i; >>------------- file 2 (pro_main.c) ---------------------- >>#define EXTERN [...] >I've seen people do this kind of thing a lot, but I've never liked >having to remeber to put #define EXTERN or some such in my code. I've >found it easiest to confine my global data to two files: >globals.h > extern int foo; [..] >and >globals.c > int foo; [...] >Comments? I guess I use a hybrid of the two methods for public library data: ------ libName.h ------ #ifdef LIBName int foo = FOO_DEFAULT; double bar; #else /* LIBName */ extern int foo; extern double bar; #endif /* else LIBName */ ------ libNameinit.c ------- #define LIBName #include <libName.h> ... ------ appication.c -------- #include <libName.h> .... This allows me initialization (see FOO_DEFAULT above) which would be awkward in the first method, and good maintainability, since the data is defined and declared in the same file. Mark Fresolone mjf@mjm.com, rutgers!mjm!mjf Melillo Consulting/MJM Software 908-873-0620/Fax 908-873-2250
enag@ifi.uio.no (Erik Naggum) (05/22/91)
"++Don;" (please use full names) writes: | | > From: grimlok@hubcap.clemson.edu (Mike Percy) | ... | > globals.h | > extern int foo; | > extern double bar; | > /* and so on, declaring all global variables */ | ... | > globals.c | > int foo; | > double bar; | > /* rest of the definitions */ | > | | Splitting the declarations off from the definitions of variables | introduced the possibility of nasty pitfalls, where somebody decides | to change the type in the .h file, and forgets to change it in | the .c file. Example: Good point. What I've done a lot is like this -- globals.h -- extern int foo; extern long bar; -- globals.c -- #include "globals.h" int foo; long bar; This lets the compiler check the types so the pitfall isn't any more. One system I delivered was later "maintained" by a PC-based humanoid with no clear idea of what he did to my code, and I was later hired to do fire-fighting for them (sigh). That "programmer" invented the brilliant -- globals.c -- #define extern /* */ #include "globals.h" I DO NOT recommend this, although it works on some compilers. </Erik> -- Erik Naggum Professional Programmer +47-2-836-863 Naggum Software Electronic Text <ERIK@NAGGUM.NO> 0118 OSLO, NORWAY Computer Communications <enag@ifi.uio.no>
volpe@camelback.crd.ge.com (Christopher R Volpe) (05/22/91)
In article <1991May21.150735.12200@convex.com>, grogers@convex.com (Geoffrey Rogers) writes: |>In non-ANSI C compiler/loader environments this may or may not work. You |>could get multiple defined symbols for i, depending upon the model that the |>compiler used for external variables. |> |>The above code in not ANSI conforming, because you do have multiple |>definitions of i. I think so far I have seen about 3 or 4 wrong answers to this question, such as the above. There is nothing wrong with the referenced code as far as the Standard is concerned. There are not multiple definitions of i, because none of those *tentative* definitions has an initializer. In such a situation, all tentative definitions are treated as a single definition with initializer 0. (See A10.2 in K&R2 for an explanation) -Chris |>+------------------------------------+---------------------------------+ |>| Geoffrey C. Rogers | "Whose brain did you get?" | |>| grogers@convex.com | "Abbie Normal!" | |>| {sun,uunet,uiucdcs}!convex!grogers | | |>+------------------------------------+---------------------------------+ ================== Chris Volpe G.E. Corporate R&D volpecr@crd.ge.com
grimlok@hubcap.clemson.edu (Mike Percy) (05/22/91)
enag@ifi.uio.no (Erik Naggum) writes: >"++Don;" (please use full names) writes: >| > From: grimlok@hubcap.clemson.edu (Mike Percy) >| Splitting the declarations off from the definitions of variables >| introduced the possibility of nasty pitfalls, where somebody decides >| to change the type in the .h file, and forgets to change it in >| the .c file. Example: >Good point. What I've done a lot is like this > -- globals.h -- > extern int foo; > extern long bar; > -- globals.c -- > #include "globals.h" > int foo; > long bar; Oops. In my haste I left this out...of course I always #include globals.h in globals.c. Bad things can happen otherwise. And of course in the makefile globals.obj : globals.c globals.h (or the equivalent with implicit rules, or better yet using automatic dependency checking). >This lets the compiler check the types so the pitfall isn't any more. >One system I delivered was later "maintained" by a PC-based humanoid >with no clear idea of what he did to my code, and I was later hired to >do fire-fighting for them (sigh). That "programmer" invented the >brilliant > -- globals.c -- > #define extern /* */ > #include "globals.h" Blech. I mean saving keystrokes is nice, but really! I usually end up writing globals.h, copy to globals.c, and globally change to get rid of the externs: <ESC>1,$s/extern// "I don't know about your brain, but mine is really...bossy." Mike Percy grimlok@hubcap.clemson.edu ISD, Clemson University mspercy@clemson.BITNET (803)656-3780 mspercy@clemson.clemson.edu
zhoumi@nff.ncl.omron.co.jp (Zhou Mi) (05/23/91)
Up to now, I've got many answers. Here, I give my thanks to all the people who gives me the answer by E-mail or by News. But, there are so many conflicting answers that I feel really confusion. Can anyone give me a proper conclusion or answer ?? First all, I give my working environment here: I'm working on : machine: OMRON HOLONIC WORKSTATION SX9100/DT OS: UNIOS-B 4.3BSD UNIX: 1.60Beta Compiler: both cc and gcc There are some of the answers , which I've get, as follows: 1) Date: Mon, 20 May 91 09:02:17 PDT From: raymond@math.berkeley.edu (Raymond Chen) Message-Id: <9105201602.AA07902@math.berkeley.edu> Received: by sunkist.berkeley.edu (4.1/1.31) id AA03310; Mon, 20 May 91 09:02:16 PDT To: zhoumi@nff.ncl.omron (Zhou Mi) Subject: Re: Correct or Not or Old-fashioned or Bug Newsgroups: comp.lang.c In-Reply-To: <ZHOUMI.91May20182038@marlboro.nff.ncl.omron.co.jp> Organization: U.C. Berkeley Status: RO Although it is incorrect(even by the old K&R standard), it works on unix (and only on unix) systems because of a bug in the linker. From raymond@math.berkeley.edu Wed May 22 03:18:37 1991 Received: by othello.nff.ncl.omron.co.jp (5.65-omron/6.3J-omron) id AA06141; Wed, 22 May 91 03:18:31 +0900 Received: from math.Berkeley.EDU by uunet.uu.net with SMTP (5.61/UUNET-uucp-primary) id AA01257; Tue, 21 May 91 11:06:58 -0400 Received: from sunkist.berkeley.edu by math.berkeley.edu (4.1/1.33(math)) id AA13916; Tue, 21 May 91 08:06:38 PDT Date: Tue, 21 May 91 08:06:38 PDT From: raymond@math.berkeley.edu (Raymond Chen) Message-Id: <9105211506.AA13916@math.berkeley.edu> To: zhoumi@nff.ncl.omron Subject: Re: Correct or Not or Old-fashioned or Bug Status: RO |Why is the BUG still alive ?? Because the BUG is a hack used by the compiler/linker to control whether or not to link stdio and/or floating point. 2) Date: Tue, 21 May 91 15:05:55 GMT From: steve@taumet.com (Stephen Clamage) X-Local-Time: Tue, 21 May 91 08:05:55 PDT To: zhoumi@nff.ncl.omron Subject: Re: Correct or Not or Old-fashioned or Bug Newsgroups: comp.lang.c References: <ZHOUMI.91May20182038@marlboro.nff.ncl.omron.co.jp> Status: RO In comp.lang.c you write: >When I am working in a project, I find that someone in my group write >the following program. Though it seems work well, I still wonder if it >is correct or better ?? [ 'int i;' included in all modules ] Most Unix systems allow a declaration like int i; to appear in more than one module. Other systems require exactly one defining instance. Technically, int i; is a defining instance, while extern int i; is not. To be portable, the header file should contain extern int i; and one module should contain int i; (It is ok to have both extern int i; int i; in the same module.) This will compile and link correctly on all systems. To avoid the problem of having to write declarations twice, here is a trick that is often used: Each header file looks like this: #ifndef EXTERN #define EXTERN extern #endif EXTERN int i; EXTERN double d; EXTERN struct foo bar; ... Then when you include any header, all the variables are declared like this: extern int i; extern double d; extern struct foo bar; In one module, such as the one including 'main()', you do this: #define EXTERN #include "file1.h" #include "file2.h" ... Here 'EXTERN' is defined to be nothing, so the declarations now look like this: int i; double d; struct foo bar; You have a single source declaration for each variable, and exactly one defining instance in the entire program for each. -- Steve Clamage, TauMetric Corp, steve@taumet.com Date: Wed, 22 May 91 8:01:36 PDT From: Stephen D. Clamage <steve@taumet.com> In-Reply-To: <9105220040.AA06573@marlboro.nff.ncl.omron.co.jp>; from "Zhou Mi" a t May 22, 91 9:40 am X-Mailer: ELM [version 2.3 PL2] Message-Id: <9105220801.AA17473@taumet.com> Status: RO > But why --- > >> Most Unix systems allow a declaration like > >> int i; > >> to appear in more than one module. > ?? This is called the "common" model, from the FORTRAN style of global variables. In FORTRAN, you didn't have global variables, but you did have named sections of memory, called COMMON blocks. Every module (in original FORTRAN, every subroutine was its own module) which referenced a COMMON block carried a declaration for it. There was no notion of a "defining instance" of a COMMON block, so the linker had to take all these named blocks and allocate them to the same address. Early Unix C compilers used the same principle. Each declaration of a global data object was given the "common" attribute, and the linker would allocate all global data items with the same name to the same address. This worked even if some were initialized. Some linkers would complain if more than one was initialized, and some would not; in the latter case, you could not necessarily predict which initial value would be used. In some environments, the linker does not support common data, or cannot reconcile an initialized item with a common item having the same name. So the most portable thing is not to use declarations which result in objects with the "common" attribute. -- Steve Clamage, TauMetric Corp, steve@taumet.com 3) From: volpe@camelback.crd.ge.com (Christopher R Volpe) Newsgroups: comp.lang.c Subject: Re: Correct or Not or Old-fashioned or Bug Date: 22 May 91 15:43:21 GMT Reply-To: volpe@camelback.crd.ge.com (Christopher R Volpe) Distribution: comp.lang.c In article <1991May21.150735.12200@convex.com>, grogers@convex.com (Geoffrey Rogers) writes: |>In non-ANSI C compiler/loader environments this may or may not work. You |>could get multiple defined symbols for i, depending upon the model that the |>compiler used for external variables. |> |>The above code in not ANSI conforming, because you do have multiple |>definitions of i. I think so far I have seen about 3 or 4 wrong answers to this question, such as the above. There is nothing wrong with the referenced code as far as the Standard is concerned. There are not multiple definitions of i, because none of those *tentative* definitions has an initializer. In such a situation, all tentative definitions are treated as a single definition with initializer 0. (See A10.2 in K&R2 for an explanation) -Chris |>+------------------------------------+---------------------------------+ |>| Geoffrey C. Rogers | "Whose brain did you get?" | |>| grogers@convex.com | "Abbie Normal!" | |>| {sun,uunet,uiucdcs}!convex!grogers | | |>+------------------------------------+---------------------------------+ ================== Chris Volpe G.E. Corporate R&D volpecr@crd.ge.com ********************************************************************** My brain is going to CORE DUMP because of lacking of memory. Thanks again for all the answers. -- +------ From: Zhou Mi ||=======||{}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{} ||\ / ||{} Zhou Mi, RZE, Systems R&D LAB., OMRON Co. {} || \ / ||{} E-mail: zhoumi@nff.ncl.omron.co.jp {} || \/ ||{} TEL: 075-951-5111 x 3176 {} || /\ ||{}=============================================================={} || / ||{} What is AI ? This is the very question that AI machine can {} ||/ ||{} answer, but one can not !! {} ||=======||{}______________________________________________________________{}
rjc@cstr.ed.ac.uk (Richard Caley) (05/24/91)
In article <ZHOUMI.91May23102519@marlboro.nff.ncl.omron.co.jp>, Zhou Mi (zm) writes:
zm> But, there are so many conflicting answers that I feel really
zm> confusion. Can anyone give me a proper conclusion or answer ??
Me too, so I caved in and asked for divine guidence.
From K&R, K&R-II and Plaughter and Brodie...
The Old testament, the book of Reference, chapter 11, verse 2:
``The apearence of the extern keyword in an external
definition indicates that storage for the identifiers being
declared will be allocated in another file. Thus in a
multi-file program, an external data definition without the
extern specifier must appear in exactly one of the files.''
The New Testament, the book of Reference, chapter 10, verse 2:
``An external object declaration that does not have an
initialiser, and does not contain the extern specifier, is a
tentative definition. [...] If no definition for the object
appears _in_the_translation_unit_, all its tentative
definitions become a single definition with initialiser 0.''
[emphasis mine].
The Commentaries:
``If a data object declaration is a tentative definition and you
write no definition for the same object later in the
translation unit, then the translater allocates storage for
the data object at the end of the translation unit.''
Someone else will have to do the Tablets of Stone.
TNT adds a comment that the multi-file version of the rule is
recognised by the standard as a common extension.
--
rjc@cstr.ed.ac.uk It was news to me too, too long on Unix.
scjones@thor.sdrc.com (Larry Jones) (05/24/91)
In article <19804@crdgw1.crd.ge.com>, volpe@camelback.crd.ge.com (Christopher R Volpe) writes: > I think so far I have seen about 3 or 4 wrong answers to this question, such > as the above. There is nothing wrong with the referenced code as far as > the Standard is concerned. There are not multiple definitions of i, because > none of those *tentative* definitions has an initializer. In such a > situation, all tentative definitions are treated as a single definition > with initializer 0. (See A10.2 in K&R2 for an explanation) Not so. WITHIN A SINGLE SOURCE FILE, multiple tentative definitions are treated as a single definition, but the cited example had them scattered across multiple files. In this case, each file would end up with a definition and the linker is justified in complaining about it. ---- Larry Jones, SDRC, 2000 Eastman Dr., Milford, OH 45150-2789 513-576-2070 Domain: scjones@sdrc.com Path: uunet!sdrc!scjones I won't eat any cereal that doesn't turn the milk purple. -- Calvin
volpe@camelback.crd.ge.com (Christopher R Volpe) (05/29/91)
In article <164@thor.sdrc.com>, scjones@thor.sdrc.com (Larry Jones) writes: |>Not so. WITHIN A SINGLE SOURCE FILE, multiple tentative definitions |>are treated as a single definition, but the cited example had them |>scattered across multiple files. In this case, each file would end |>up with a definition and the linker is justified in complaining about |>it. Oops. Thanks. The small print on page 227 of K&R2 says that the behavior I described is a common extension under Unix, but not Standard behavior. |>---- |>Larry Jones, SDRC, 2000 Eastman Dr., Milford, OH 45150-2789 513-576-2070 |>Domain: scjones@sdrc.com Path: uunet!sdrc!scjones |>I won't eat any cereal that doesn't turn the milk purple. -- Calvin ================== Chris Volpe G.E. Corporate R&D volpecr@crd.ge.com