mccarrol@topaz.rutgers.edu (<MC>) (01/18/88)
I have a couple of questions concerning the extern qualifier in C. First: Is it possible to put an external declaration outside the body of any function? I'm writing a large program in several separate modules, and I'd like to have a listing at the beginning of each file of what external variables are used in the file. Can extern be used this way? Second: I know that my compiler doesn't complain against extern's outside of function bodies, but I'm not sure if it does what I want. Is the compiler allocating space for these variables, or is it just identifying thier names as a reference to something from another source file, to be resolved at link-time? Just in case it matters ( although I doubt it; this MUST be standardized, right?) I'm using Lattice C 3.10 on an Amiga. <MC> -- "It is a principle of the music/to repeat the theme |Mark C. Carroll Repeat/and repeat again/as the pace mounts. /------/Rutgers U CS Student The theme/is difficult/but no more difficult |ARPA :CARROLL@AIM.RUTGERS.EDU than the facts to be/resolved"-WC Williams |Usenet:mccarrol@topaz.rutgers.edu
gwyn@brl-smoke.ARPA (Doug Gwyn ) (01/18/88)
In article <17428@topaz.rutgers.edu> mccarrol@topaz.rutgers.edu (<MC>) writes: >First: Is it possible to put an external declaration outside the body >of any function? Sure, In fact, that's my usual approach. Some people who like the idea of an "import" specifier always put their extern declarations inside their function bodies. >I'm writing a large program in several separate >modules, and I'd like to have a listing at the beginning of each file >of what external variables are used in the file. Can extern be used >this way? Yes. Note that this conveniently supports having a module-specific header file that contains extern declarations for all module entry points and global data (i.e. a module interface specification header), with the same header #included in the source code for the module itself. >Second: I know that my compiler doesn't complain against extern's >outside of function bodies, but I'm not sure if it does what I want. >Is the compiler allocating space for these variables, or is it just >identifying thier names as a reference to something from another >source file, to be resolved at link-time? Not quite either. There are two possible methods of implementation of extern data in C, but the model you should think of is: If it says "extern", it is a reference to something allocated elsewhere; if it doesn't say "extern", it allocates storage, and of course storage should be allocated for an object precisely once among all the modules for an application. The module interface specification header I mentioned above must, therefore, declare all its global data as "extern", in order to not allocate it in every file that #includes the header. "extern" does not necessarily mean "in another source file"; the actual definition can also occur elsewhere in the same source file.
john13@garfield.UUCP (John Russell) (01/19/88)
In article <7123@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
]>Is the compiler allocating space for these variables, or is it just
]>identifying thier names as a reference to something from another
]>source file, to be resolved at link-time?
]
]Not quite either. There are two possible methods of implementation
]of extern data in C, but the model you should think of is: If it
]says "extern", it is a reference to something allocated elsewhere;
That is the way you should think about it, but if you do something like this:
file 1 -
int fou;
...
file 2 -
extern int foo;
...
foo = 1;
then at least some compilers will run this properly (no warnings even).
John
--
"A Chinese soldier in Tibet who tried to tear off a British woman's Sergeant
Bilko T-shirt has become the first known case of someone mistaking Phil
Silvers for the Dalai Lama."
-- Toronto Globe & Mail, Nov. 14/87
gwyn@brl-smoke.ARPA (Doug Gwyn ) (01/21/88)
In article <4405@garfield.UUCP> john13@garfield.UUCP (John Russell) writes: -In article <7123@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: -] Not quite either. There are two possible methods of implementation -] of extern data in C, but the model you should think of is: If it -] says "extern", it is a reference to something allocated elsewhere; -That is the way you should think about it, but if you do something like this: -file 1 - -int fou; [I assume "foo" was intended] -file 2 - -extern int foo; -foo = 1; -then at least some compilers will run this properly (no warnings even). PLEASE don't do this. A compiler is not obliged to make this example "work". That is why you should think the way I said; C compilers are obliged to always make that approach work right.
john13@garfield.UUCP (John Russell) (01/23/88)
In article <7150@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: >In article <4405@garfield.UUCP> john13@garfield.UUCP (John Russell) writes: >-file 1 - >-int fou; >[I assume "foo" was intended] Not the point. This exact situation happened to me (with different variable names of course). DAMN tough to track down! Luckily I noticed the typo shortly after it occurred (after running the program once). >-file 2 - >-extern int foo; >-foo = 1; >-then at least some compilers will run this properly (no warnings even). >PLEASE don't do this. A compiler is not obliged to make this example >"work". No kidding :-). But I do think it's important to know of this peculiar behaviour, which could easily cause hard-to-find errors when using "extern". The original article seemed to be asking *how* extern storage was treated, and this example shows how the compiler doesn't always behave as you would assume under an "ideal" model of C. This was the C on our 4.3BSD system. I was shocked that the linker didn't complain at all that I was extern'ing a variable, then referring to it, when it didn't exist in any other module. John -- "Am I dreaming, or was there a show on this weekend called 'Jimmy the Greek: Live at the Apollo'?" -- David Letterman
tainter@ihlpg.ATT.COM (Tainter) (01/24/88)
In article <7150@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA (Doug Gwyn ) writes: > In article <4405@garfield.UUCP> john13@garfield.UUCP (John Russell) writes: > -file 1 - > int fou; > [I assume "foo" was intended] I assume your assumption also. > -file 2 - > extern int foo; > foo = 1; I assume this last line was supposed to be a static initialization. No C compiler accepts this. If you have something, supposedly a C compiler, that accepts this then you have been lied to. Clearly, that compiler is for some language very similar to C, but not C. > PLEASE don't do this. A compiler is not obliged to make this example > "work". In fact, C compilers should be obliged to complain about this as it does not conform to the syntax of C. --j.a.tainter
john13@garfield.UUCP (John Russell) (01/25/88)
In article <4694@ihlpg.ATT.COM> tainter@ihlpg.ATT.COM (Tainter) writes: >> In article <4405@garfield.UUCP> john13@garfield.UUCP (John Russell) writes: >> -file 1 - >> int fou; [ ^^^ this is a combination intentional typo and French pun ] >> -file 2 - >> extern int foo; >> foo = 1; > >I assume this last line was supposed to be a static initialization. Oops, no, not a static initialization but one somewhere later on, within a function. The point I wanted to make was that even if the variable is _never_ declared except as extern, the compiler may in fact allocate it for you and let you refer to it without complaining. The code even works properly. However if you had 100 references to the variable "long_variable_name" in file1, and 100 references to the variable "long_varaible_name" (sic!) in file2, you could easily be operating under the assumption that they were the same variable if you were using extern. John -- "You are lying scum!" -- member of Parliament James Fulton was expelled for saying this to Canadian Prime Minister Brian Mulroney; use of the word "lying" was deemed unparliamentary, although the "scum" was acceptable
jbeard@quintus.UUCP (Jeff Beard) (01/30/88)
Note however, that the practice of multiple definitions of a specific global variable is extreamly poor, even IF corrected by a link/loader. Some have been so lax as to forget that one defines ONLY once, and references all other occurances. Using this model, one would never attempt to use compile time initializer for a reference and good coding practice yeilds a win win!
emz@bjcong.bj.co.uk (ED ZIETARSKI) (06/28/90)
In article <111254@linus.mitre.org>, cookson@helios.mitre.org (Dean Cookson) writes: > I know that if you have an extern that is an array, you don't have to use > the size of the array in the extern declaration, you only need it in > the original declaration. But is it an error to include it in the > extern declaration?? > > ie: > file1.c > int myarray[10]; > > file2.c > extern int myarray[10]; I would say it is an error because if you or someone else changes the array size at a later stage, (s)he would have to also know/remember that the external declaration needs changing. Even if you use a #define for the array size, you could still have the situation arising of someone deciding to use a *different* preprocessor definition name. The compiler cannot pick up differences in array sizes in a set of objects and neither can the linker (as far as I know !) --- Ed Zietarski, Boldon James Limited, Congleton, CHESHIRE CW12 1JN, UK. emz@bj.co.uk (UK only) emz@boldon-james-limited.co.uk (Internet) ..!mcsun!ukc!pyrltd!bjcong!emz
steve@taumet.com (Stephen Clamage) (06/29/90)
In article <910@bjcong.bj.co.uk> emz@bjcong.bj.co.uk (ED ZIETARSKI) writes: >In article <111254@linus.mitre.org>, cookson@helios.mitre.org (Dean Cookson) writes: >> I know that if you have an extern that is an array, you don't have to use >> the size of the array in the extern declaration, you only need it in >> the original declaration. But is it an error to include it in the >> extern declaration?? >> ... >I would say it is an error because if you or someone else changes the array size >at a later stage, (s)he would have to also know/remember that the external >declaration needs changing. Well, it may be a poor idea, but that is not the same thing as an error. It is not an error. The usual way to avoid the logistical problem of maintaining multiple declarations is to put declarations needed by more than one file into a header file and #include the header file where needed. In a big program, multiple such header files may be appropriate. In this example, you would then have the declaration extern int foo[20]; in the header file. A C program which strictly conforms to the ANSI C standard must have a defining instance of this array as well as this declaration. Some C implementations require the separate defining instance and some do not. The usual trick is then to do something like this: header.h: #ifndef EXTERN #define EXTERN extern #endif EXTERN int foo[20]; EXTERN double bar; ... In all but the file containing main(), you simple #include header.h, and in main.c: #define EXTERN #include "header.h" ... Now every file which includes header.h has an extern declaration for the global identifiers, and main.c has defining instances for them. This is the most portable solution I know of, and strictly conforms to ANSI C. -- Steve Clamage, TauMetric Corp, steve@taumet.com
karl@haddock.ima.isc.com (Karl Heuer) (07/01/90)
In article <277@taumet.com> steve@taumet.UUCP (Stephen Clamage) writes: >The usual trick is then to do something like this: > #define EXTERN extern In rebuttal, I'd like to mention that many of us find this grotesque, and prefer to use /* header.h */ extern int foo[20]; extern double bar; /* something.c */ #include "header.h" int foo[20]; double bar = 3.0; which is also completely portable, doesn't require preprocessor games, and allows the objects to have initializers (this can sometimes be done with your method too, but it makes it even uglier). Since the defining source file also includes the header, you can't get them out of sync. Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint
hannum@haydn.psu.edu (Charles Hannum) (07/05/90)
In article <16994@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes: In article <277@taumet.com> steve@taumet.UUCP (Stephen Clamage) writes: >The usual trick is then to do something like this: > #define EXTERN extern In rebuttal, I'd like to mention that many of us find this grotesque, and prefer to use /* header.h */ extern int foo[20]; extern double bar; /* something.c */ #include "header.h" int foo[20]; double bar = 3.0; which is also completely portable, doesn't require preprocessor games, and allows the objects to have initializers (this can sometimes be done with your method too, but it makes it even uglier). Since the defining source file also includes the header, you can't get them out of sync. Some of us also find your method grotesque, because we have to alter the definition in *two* places rather than one if we change it. Speaking of which, why didn't ANSI specify that initializers on externs should be ignored? This would be really keen for the former type of definitions. "... preprocessor games, ..."? It's not a game. It's a perfectly ligitimate use of the C preprocessor. If we weren't supposed to use it, it wouldn't be included (based C's minimalist philosophy). -- Virtually, Charles Martin Hannum "Those who say a thing cannot be done should Please send mail to: under no circumstances stand in the way of hannum@schubert.psu.edu he who is doing it." - a misquote
steve@taumet.com (Stephen Clamage) (07/07/90)
In article <1990Jul5.044045.1534@acc.stolaf.edu> hannum@haydn.psu.edu (Charles Hannum) writes: >... why didn't ANSI specify that initializers on externs should be >ignored? This would be really keen for the former type of definitions. The problem here is that the keyword "extern" can mean either "external" (defined elsewhere) or "global" (defined here) depending on context. To simplify a bit, for data objects it means external if there is no initializer, global if there is. For functions, the external/global meaning is determined solely by the presence of a function body. I don't think that anyone will argue that this is a wonderful convention, but the ANSI committee inherited it from long C practice. Introducing extern and global keywords as used in other languages (notably assembler) would have had the advantage of precision, but would have broken many (most?) existing programs. -- Steve Clamage, TauMetric Corp, steve@taumet.com
karl@haddock.ima.isc.com (Karl Heuer) (07/07/90)
In article <1990Jul5.044045.1534@acc.stolaf.edu> hannum@haydn.psu.edu (Charles Hannum) writes: >In article <16994@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes: >>[Rather than the `#define EXTERN' hack, many of us prefer to use `extern' in >>the header and a defining instance in one source file, which also includes >>the same header. This] is also completely portable, doesn't require >>preprocessor games, and allows the objects to have initializers ... [and] >>you can't get them out of sync. >Some of us also find your method grotesque, because we have to alter the >definition in *two* places rather than one if we change it. If you change something as fundamental as the type of an object, you probably have to change every reference in *every* source file. If it's sufficiently abstract that you don't, then use a typedef, and change only the header. >"... preprocessor games, ..."? It's not a game. It's a perfectly ligitimate >use of the C preprocessor. If we weren't supposed to use it, it wouldn't be >included (based C's minimalist philosophy). This argument applies equally well to all sorts of preprocessor abuse, all strictly legal C. Sorry, I don't buy it. Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint
leo@ehviea.ine.philips.nl (Leo de Wit) (07/07/90)
In article <1990Jul5.044045.1534@acc.stolaf.edu> hannum@haydn.psu.edu (Charles Hannum) writes: | |In article <16994@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes: | | In article <277@taumet.com> steve@taumet.UUCP (Stephen Clamage) writes: | >The usual trick is then to do something like this: | > #define EXTERN extern | | In rebuttal, I'd like to mention that many of us find this grotesque, and | prefer to use | /* header.h */ | extern int foo[20]; | extern double bar; | | /* something.c */ | #include "header.h" | int foo[20]; | double bar = 3.0; | which is also completely portable, doesn't require preprocessor games, and | allows the objects to have initializers (this can sometimes be done with your | method too, but it makes it even uglier). Since the defining source file also | includes the header, you can't get them out of sync. | | |Some of us also find your method grotesque, because we have to alter the |definition in *two* places rather than one if we change it. Apparently another mix-up of declarations (which I feel belong in header files) and definitions (which I feel belong in source files). If you find this grotesque, why make a difference for function declarations/definitions? Be consequent and have the body of the function conditionally included in the header file ... I'd also like to know how the 'extern-trick-advocates' handle multiple include files; each would need its own EXTERN macro (and guess what mysterious failures happen if you misspell them in the source file). And then I'm not even talking about nested include files. [] |"... preprocessor games, ..."? It's not a game. It's a perfectly ligitimate |use of the C preprocessor. If we weren't supposed to use it, it wouldn't be |included (based C's minimalist philosophy). Whether or not this is a perfectly legitimate use of the C preprocessor is not the issue. I'm sure the Obfuscated C Code Contest will give us again lots of perfectly legitimate programs, showing us how NOT to code. Leo. #define EXTERN GROTESQUE
imp@dancer.Solbourne.COM (Warner Losh) (07/10/90)
In article <1990Jul5.044045.1534@acc.stolaf.edu> hannum@haydn.psu.edu (Charles Hannum) writes: >"... preprocessor games, ..."? It's not a game. It's a perfectly >ligitimate [sic] use of the C preprocessor. If we weren't supposed >to use it, it wouldn't be included (based C's minimalist philosophy). Yah, right. And I'd suppose that you think the following is also legal and not a "preprocessor game": #include "pascal.h" main() BEGIN int foo; IF (foo) THEN BEGIN WRITE ("Fooing today\n"); END ELSE BEGIN WRITE ("No foos today\n"); END END The above, while strictly speaking IS 'C' (depending on the defines in pascal.h, that is), I'd hate to have to maintain something like that. #define EXTERN extern is a gross preprocessor game that should be avoided, just as the above cute pascal example should be avoided. -- Warner Losh imp@Solbourne.COM Boycott Lotus. #include <std/disclaimer>
stever@Octopus.COM (Steve Resnick ) (07/10/90)
In article <1990Jul9.190744.1437@Solbourne.COM> imp@dancer.Solbourne.COM (Warner Losh) writes: >In article <1990Jul5.044045.1534@acc.stolaf.edu> hannum@haydn.psu.edu >(Charles Hannum) writes: >>"... preprocessor games, ..."? It's not a game. It's a perfectly >>ligitimate [sic] use of the C preprocessor. If we weren't supposed >>to use it, it wouldn't be included (based C's minimalist philosophy). > >Yah, right. And I'd suppose that you think the following is also >legal and not a "preprocessor game": > >#include "pascal.h" > >main() >BEGIN > int foo; > > IF (foo) THEN > BEGIN > WRITE ("Fooing today\n"); > END > ELSE > BEGIN > WRITE ("No foos today\n"); > END >END > >The above, while strictly speaking IS 'C' (depending on the defines in >pascal.h, that is), I'd hate to have to maintain something like that. >#define EXTERN extern is a gross preprocessor game that should be >avoided, just as the above cute pascal example should be avoided. > I wish the boys in Redmond Washington would adhere to that philosophy. After spending a weekend debugging some OS/2 code I have learned to loathe dearly MS's macros. In the OS/2 programmers refrences, Quick Help, and other MS blessed/produced products they all refer to these "improved" types and declarations. an example is: #define EXTERN extern #define far FAR #define pascal PASCAL What's wrong with extern far pascal foo() vs EXTERN FAR PASCAL foo()? And why should I use "SEL n" when I mean "unsigned n"? I would bitch a lot less if I didn't have to have MANY books open to figure out what these silly things meant! (oddly enough, if I ask MSC to generate protos for my EXTERN FAR PASCAL functions, they get generated correctly..) Seems like we keep working towards standardization and someone in the infinite glory wants to change it for us.... *sigh* Steve -- -------------------------------------------------------------------------------- Steve Resnick -<stever@octopus.COM apple!octopus!stever sun!vsi1!octopus!stever> 408/241-1533 Process Scientific, Inc. "0x2B|~0x2B THAT is the question!"
peter@ficc.ferranti.com (Peter da Silva) (07/10/90)
In article <1990Jul10.004710.20500@Octopus.COM> stever@octopus.UUCP (Steve Resnick ) writes: > What's wrong with extern far pascal foo() vs EXTERN FAR PASCAL foo()? Nothing. > And why should I use "SEL n" when I mean "unsigned n"? I don't know. Why should you use "FILE *fp" instead of "struct _iob *fp"? -- Peter da Silva. `-_-' +1 713 274 5180. <peter@ficc.ferranti.com>
lerman@stpstn.UUCP (Ken Lerman) (07/11/90)
In article <1990Jul10.004710.20500@Octopus.COM> stever@octopus.UUCP (Steve Resnick ) writes: [.... stuff deleted ....] > >I wish the boys in Redmond Washington would adhere to that philosophy. >After spending a weekend debugging some OS/2 code I have learned to loathe >dearly MS's macros. In the OS/2 programmers refrences, Quick Help, and other >MS blessed/produced products they all refer to these "improved" types and >declarations. an example is: > >#define EXTERN extern >#define far FAR >#define pascal PASCAL > >What's wrong with extern far pascal foo() vs EXTERN FAR PASCAL foo()? >And why should I use "SEL n" when I mean "unsigned n"? I would bitch a lot >less if I didn't have to have MANY books open to figure out what these silly >things meant! (oddly enough, if I ask MSC to generate protos for my EXTERN >FAR PASCAL functions, they get generated correctly..) > >Seems like we keep working towards standardization and someone in the infinite >glory wants to change it for us.... *sigh* > >Steve Resnick -<stever@octopus.COM apple!octopus!stever sun!vsi1!octopus!stever> >408/241-1533 Process Scientific, Inc. >"0x2B|~0x2B THAT is the question!" What is wrong is that far and pascal aren't ANSI C to begin with. And Microsoft has decided that for version 6.0, "__far" is better than "far" (because ANSI reserves identifiers beginning with "__" to the compiler writer.) So if you followed the Microsoft "standard", all you have to do is use the new set of macros and your code works. Then if you would like to port your code to some other machine, you can #define FAR to nothing. At least Microsoft has an excuse for the near/far crap we have to put up with. They can blame it on the wizards at Intel who decided that compatibility with previous chips is more important than usability. The jerks at DEC screwed up external references all by themselves. Rather than change some of their other software, they decided to foist off their poor excuse for a compiler as C under VMS. Ken
bright@Data-IO.COM (Walter Bright) (07/14/90)
In article <5353@stpstn.UUCP> lerman@stpstn.UUCP (Ken Lerman) writes: <In article <1990Jul10.004710.20500@Octopus.COM> stever@octopus.UUCP (Steve Resnick ) writes: <<In the OS/2 programmers refrences, Quick Help, and other <<MS blessed/produced products they all refer to these "improved" types and <<declarations. an example is: << <<#define EXTERN extern <<#define far FAR <<#define pascal PASCAL << <<What's wrong with extern far pascal foo() vs EXTERN FAR PASCAL foo()? <Microsoft has decided that for version 6.0, "__far" is better than "far" <So if you followed the Microsoft "standard", all you have to do is use <the new set of macros and your code works. <Then if you would like to port your code to some other machine, you <can #define FAR to nothing. The FAR macro is still entirely unnecessary. To port to a machine that does not have far: #define far To port to the new _far keyword: #define far _far There is no point to the FAR macro (and the other similar ones).
david@csource.oz.au (david nugent) (07/15/90)
In <2569@dataio.Data-IO.COM> bright@Data-IO.COM (Walter Bright) writes: ><<#define EXTERN extern ><<#define far FAR ><<#define pascal PASCAL ><< ><<What's wrong with extern far pascal foo() vs EXTERN FAR PASCAL foo()? ><Microsoft has decided that for version 6.0, "__far" is better than "far" ><So if you followed the Microsoft "standard", all you have to do is use ><the new set of macros and your code works. ><Then if you would like to port your code to some other machine, you ><can #define FAR to nothing. >The FAR macro is still entirely unnecessary. To port to a machine that does >not have far: >#define far >To port to the new _far keyword: >#define far _far >There is no point to the FAR macro (and the other similar ones). While technically that's quite correct, I use uppercased macros for type declarators and moderators purely as a reminder that it isn't supported in all environments in which the code may be compiled. I even use EXTERN, VOLATILE, STATIC and a few others, with one include file "environ.h" which takes care of the specific environment. I find that it helps in reminding me not to rely on environment and/or compiler specific features unless I specifically #ifdef the code. It probably helps make the code more readable too. -- _______________________________________________________________________________ Unique Computing Pty Ltd Melbourne Australia - Communications Specialists david@csource.oz.au 3:632/348@fidonet 28:4100/1@signet