Static Variables Storage

42 views
Skip to first unread message

chandrakant yemparala

unread,
Sep 21, 2000, 3:00:00 AM9/21/00
to
I have a dumb question: Are external static variables allocated storage in
stack or the heap?

thanks
chandra

Ben Pfaff

unread,
Sep 21, 2000, 3:00:00 AM9/21/00
to
"chandrakant yemparala" <cyem...@email.mot.com> writes:

> I have a dumb question: Are external static variables allocated storage in
> stack or the heap?

No.

Kaz Kylheku

unread,
Sep 21, 2000, 3:00:00 AM9/21/00
to
On Thu, 21 Sep 2000 13:32:12 -0500, chandrakant yemparala
<cyem...@email.mot.com> wrote:
>I have a dumb question: Are external static variables allocated storage in
>stack or the heap?

The C language doesn't define these concepts. There are three kinds of storage
in C: static, automatic and (dynamically) allocated.

Objects created by external definitions (that is, outside of any function,
at file scope) have static storage. These objects persist throughout the
lifetime of the program.

Objects defined in statement blocks, without the storage class ``static''
have automatic storage, whose lifetime is tied to that execution of the block.

Objects created by the functions malloc, realloc or calloc are in allocated
storage, which persist until explicitly deallocated.

--
Any hyperlinks appearing in this article were inserted by the unscrupulous
operators of a Usenet-to-web gateway, without obtaining the proper permission
of the author, who does not endorse any of the linked-to products or services.

Dann Corbit

unread,
Sep 21, 2000, 3:00:00 AM9/21/00
to
"chandrakant yemparala" <cyem...@email.mot.com> wrote in message
news:8qdk7b$mp...@nntp.cig.mot.com...

> I have a dumb question: Are external static variables allocated storage in
> stack or the heap?

The words you seek are "from automatic storage" <==> "stack"
and "from the free store" or "from allocated storage" <==> "heap"

There are three storage durations: static, automatic, and allocated.

An auto variable (called stack or stack-frame by many) exists for the
duration of the function call and is not initialized unless done so
explicitly by the programmer. A static variable lasts for the duration of
the entire program and is initialized to zero unless explicitly initialized
to something else by the programmer. So this memory does not behave like an
automatic variable's memory.

An object allocated by malloc()/realloc() is also not initialized and the
duration of the object is from the time of allocation to the time of free()
or program termination. So an external static does not behave like this
either.

An object allocated by calloc() is similar to static (except for duration)
in that the memory is zero initialized. However, calloc() may not correctly
initialize non-integral types such as pointers and floating point values,
since the internal representation of NULL is not necessarily zero, and the
internal representations of 0.0, 0.0f, and 0.0L are not necessarily zero.
Hence, an external static does not behave like calloc().

So any public variables such as static variables or global variables are a
third class of allocation. The standard does say this:
"All objects with static storage duration shall be initialized (set to their
initial values) before program startup. The manner and timing of such
initialization are otherwise unspecified."

--
C-FAQ: http://www.eskimo.com/~scs/C-faq/top.html
"The C-FAQ Book" ISBN 0-201-84519-9
C.A.P. Newsgroup http://www.dejanews.com/~c_a_p
C.A.P. FAQ: ftp://38.168.214.175/pub/Chess%20Analysis%20Project%20FAQ.htm

Richard Heathfield

unread,
Sep 21, 2000, 3:00:00 AM9/21/00
to
chandrakant yemparala wrote:
>
> I have a dumb question: Are external static variables

No such thing.

> allocated storage in stack or the heap?

Not necessarily, even if there were such a thing as an external static
variable.


--
Richard Heathfield
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
65 K&R Answers: http://users.powernet.co.uk/eton/kandr2/index.html (32
to go)

-hs-

unread,
Sep 21, 2000, 3:00:00 AM9/21/00
to
Ben Pfaff a écrit dans le message <87vgvpe...@pfaffben.user.msu.edu>...
>"chandrakant yemparala" <cyem...@email.mot.com> writes:
>
>> I have a dumb question: Are external static variables allocated storage

in
>> stack or the heap?
>
>No.

Ha ha !

--
-hs- Tabs out, spaces in.
CLC-FAQ: http://www.eskimo.com/~scs/C-faq/top.html
ISO-C Library: http://www.dinkum.com/htm_cl
FAQ de FCLC : http://www.isty-info.uvsq.fr/~rumeau/fclc
C-tips: http://jackklein.home.att.net


Garen Parham

unread,
Sep 21, 2000, 3:00:00 AM9/21/00
to

"Richard Heathfield" <bin...@eton.powernet.co.uk> wrote in message
news:39CA6EB6...@eton.powernet.co.uk...

> chandrakant yemparala wrote:
> >
> > I have a dumb question: Are external static variables
>
> No such thing.

>
> > allocated storage in stack or the heap?
>
> Not necessarily, even if there were such a thing as an external static
> variable.
>
>

Is an object declared with extern at global scope which inherits a variable
of static storage class not an "external static variable"?

-Garen

Ben Pfaff

unread,
Sep 21, 2000, 3:00:00 AM9/21/00
to
"Garen Parham" <nos...@garen.net> writes:

> Is an object declared with extern at global scope which
> inherits a variable of static storage class not an "external
> static variable"?

Er, what? "inherits"? Show us some code.
--
"Give me a couple of years and a large research grant,
and I'll give you a receipt." --Richard Heathfield

Kaz Kylheku

unread,
Sep 21, 2000, 11:13:57 PM9/21/00
to
On Thu, 21 Sep 2000 19:26:15 -0700, Garen Parham <nos...@garen.net> wrote:
>Is an object declared with extern at global scope which inherits a variable
>of static storage class not an "external static variable"?

C doesn't support inheritance. It's not clear what an external variable is; it
is either simply a file scope object---one introduced by an external definition
(as in, outside of any statement block). Or it may mean a variable with
external linkage, which is a kind of file scope variable that is defined with
the static specifier to make it private to the surrounding translation unit.

The term ``external'' has these two distinct meanings in C: there are external
definitions, which can introduce external names or internal names.

Garen Parham

unread,
Sep 22, 2000, 3:00:00 AM9/22/00
to

"Ben Pfaff" <pfaf...@msu.edu> wrote in message
news:87r96dc...@pfaffben.user.msu.edu...

> "Garen Parham" <nos...@garen.net> writes:
>
> > Is an object declared with extern at global scope which
> > inherits a variable of static storage class not an "external
> > static variable"?
>
> Er, what? "inherits"? Show us some code.

Whoops. I suppose the word "inherits" is a bad choice of words. I don't
mean inheritance as in the C++ concept. When the poster said "external
static variable", I interpreted that to mean a variable declared using the
keyword extern and which had static storage class, which global variables
have.

Quote from K&R2 A4.1 pg 195:
"There are two storage classes: automatic and static."
...
"The objects declared outside all blocks, at the same level as function
definitions, are always static."

So, I don't know whats wrong with the term "external static variable" which
Richard said there was no such thing. An arbitrary concrete example could
be:

extern int foo;

int main() { /* code here */ return 0; }

-Garen

Chris Torek

unread,
Sep 23, 2000, 3:00:00 AM9/23/00
to
In article <H%Vy5.35147$zK.3...@news.uswest.net>
Garen Parham <nos...@garen.net> writes:
>... When the [original] poster said "external static variable", I

>interpreted that to mean a variable declared using the keyword extern
>and which had static storage class, which global variables have.
>
>Quote from K&R2 A4.1 pg 195:
>"There are two storage classes: automatic and static."
>...
>"The objects declared outside all blocks, at the same level as function
>definitions, are always static."

There is a terminology problem here: the C standards use the word
"storage duration", not "storage class". (C89 lists two, but C99
fixes a problem with C89, and lists three: static, automatic, and
"allocated". Objects created by malloc() and destroyed by free()
have "allocated duration" -- even in C89.)

>So, I don't know whats wrong with the term "external static variable" ...

There is another problem with terminology here: someone who says
"static variable" might mean *either* "variable declared using the
static keyword" *or* "variable with static duration", and someone
who says "external variable" might mean "variable declared using
the extern keyword" *or* "variable with external linkage". So
that makes four possible interpretations:

variable with "static" keyword and "extern" keyword
variable with "static" keyword and external linkage
variable with static duration and "extern" keyword
variable with static duration and external linkage

Of those four, at least one is an "impossible" combination: a
variable declared with the "static" keyword can never have external
linkage. (The only possibilities are internal linkage or no linkage.
If an identifier appears with both internal and external linkage
within a single translation unit, the behavior is undefined.)

If you have managed to follow all that -- or even if not -- then
consider these examples:

/* begin translation unit */
int v1;
static int v2;
void f(void) {
int v3;
static int v4;
extern int v5;
}
extern int v6;
static int v7;
extern int v7; /* yes, v7 again -- see below */
/* end translation unit */

The declarations for v1 and v2 have file scope, so they will always
have some kind of linkage, and always have static duration. Thus,
the variable "v1" has external linkage and static duration. Adding
the "static" keyword changes the linkage to internal, so "v2" has
internal linkage and static duration.

On the other hand, the variables "v3" and "v4" have block scope.
By default, they will have automatic duration and no linkage. (The
"extern" keyword can give such variables linkage, as well as changing
their duration.) In this case, adding the "static" keyword no longer
affects linkage -- there is no linkage to affect -- and instead it
changes the duration. Here variable "v4" has static duration instead
of automatic.

The "extern" keyword is even more bizarre. Its effect depends on
whether there is a declaration of the same variable in scope yet.
If there *is* a visible declaration, "extern" refers back to its
linkage; if not, "extern" gives the variable external linkage.
Here there is no declaration yet for v5 or v6, so "extern" gives
them both external linkage. The declaration for v5 has block scope,
so it would normally have automatic duration, but when the extern
keyword gives it linkage, it also changes its duration to static.

The declaration for v6 is at file scope, so it already has external
linkage and static duration, making the "extern" keyword *almost*
extraneous. The only thing "extern" does in this case is "mark"
the declaration as "not even a tenative definition". At the end
of the translation unit, variables v1 and v2 -- both declared at
file scope and neither ever having been declared using an initializer
-- are both "tenative definitions". At this point, they both turn
into actual definitions. Space is set aside for them, and they
are initialized as if they had been set equal to zero (as in "int
v1 = 0;") by the time the program gets to main(). The declaration
for variable v6, however, is not even a tenative definition: it is
just a declaration. No space is set aside, and presumably, some
other translation unit will actually *define* variable "v6".

For variable "v7", we first have a tenative definition using the
"static" keyword: "static int v7;". This gives v7 static duration
and internal linkage. This declaration is still in scope (i.e.,
is visible) at the next line -- the "extern" declaration -- so
the "extern" keyword here refers back to the previous declaration,
and uses the same linkage. Thus, in *this* case, "extern int v7;"
means "give v7 static duration and internal linkage again."

>Richard said there was no such thing.

Here is an example of an erroneous construct:

/* begin incorrect translation unit */
extern int erroneous; /* ok so far... */
static int erroneous; /* WRONG */
/* end incorrect translation unit */

In this case, we first declare (but do not define, even tenatively)
the variable "erroneous" at file scope, using the "extern" keyword.
This gives the identifier external linkage. The very next line
declares the same identifier again, but this time gives it internal
linkage. This is an error, and the effect is undefined. Here
someone might try to refer to "erroneous" as an "external static
variable", and indeed, there is no such thing.

(If you try this with actual compilers, you find that many of them
wind up simply giving the identifier internal linkage. Or in some
cases, you might find something really bizarre:

% cat file1.c
int three = 3;
% cat file2.c
#include <stdio.h>

extern int three;
void show_three(void) {
printf("extern int three = %d\n", three);
}

static int three = 42;
int main(void) {
printf("static int three = %d\n", three);
show_three();
return 0;
}
% cc -o bizarre file1.c file2.c

On some systems -- not including mine -- the result may be an
executable that prints "static int three = 42" and then "extern
int three = 3".)
--
In-Real-Life: Chris Torek, Berkeley Software Design Inc
El Cerrito, CA, USA Domain: to...@bsdi.com +1 510 234 3167
http://claw.bsdi.com/torek/ (not always up) I report spam to abuse@.

Richard Heathfield

unread,
Sep 23, 2000, 3:00:00 AM9/23/00
to
Garen Parham wrote:
>
> "Ben Pfaff" <pfaf...@msu.edu> wrote in message
> news:87r96dc...@pfaffben.user.msu.edu...
> > "Garen Parham" <nos...@garen.net> writes:
> >
> > > Is an object declared with extern at global scope which
> > > inherits a variable of static storage class not an "external
> > > static variable"?
> >
> > Er, what? "inherits"? Show us some code.
>
> Whoops. I suppose the word "inherits" is a bad choice of words. I don't
> mean inheritance as in the C++ concept. When the poster said "external

> static variable", I interpreted that to mean a variable declared using the
> keyword extern and which had static storage class, which global variables
> have.
>
> Quote from K&R2 A4.1 pg 195:
> "There are two storage classes: automatic and static."
> ...
> "The objects declared outside all blocks, at the same level as function
> definitions, are always static."
>
> So, I don't know whats wrong with the term "external static variable" which
> Richard said there was no such thing. An arbitrary concrete example could
> be:
>
> extern int foo;

AFAICT this is a file scope variable with external linkage. Is there
some reason for thinking otherwise?

The other side of the coin would be static int bar; - file scope
variable with internal linkage. Perhaps we're violently agreeing? Not
sure.

>
> int main() { /* code here */ return 0; }

--

Lawrence Kirby

unread,
Sep 23, 2000, 3:00:00 AM9/23/00
to
In article <8qhm3m$3pg$1...@elf.bsdi.com> to...@elf.bsdi.com "Chris Torek" writes:

...

>There is another problem with terminology here: someone who says
>"static variable" might mean *either* "variable declared using the
>static keyword" *or* "variable with static duration", and someone
>who says "external variable" might mean "variable declared using
>the extern keyword" *or* "variable with external linkage".

Or as far as the standard is concerned an external declaration is simply
one at file scope.

> So
>that makes four possible interpretations:
>
> variable with "static" keyword and "extern" keyword
> variable with "static" keyword and external linkage

variable with "static" keyword at file scope

> variable with static duration and "extern" keyword
> variable with static duration and external linkage

variable with static duration at file scope

however all variables at file scope have static duration.

...


> static int v7;
> extern int v7; /* yes, v7 again -- see below */
> /* end translation unit */

...

>For variable "v7", we first have a tenative definition using the
>"static" keyword: "static int v7;". This gives v7 static duration
>and internal linkage. This declaration is still in scope (i.e.,
>is visible) at the next line -- the "extern" declaration -- so
>the "extern" keyword here refers back to the previous declaration,
>and uses the same linkage. Thus, in *this* case, "extern int v7;"
>means "give v7 static duration and internal linkage again."

It sort of "inherits" internal linkage from the static declaration. :-)

--
-----------------------------------------
Lawrence Kirby | fr...@genesis.demon.co.uk
Wilts, England | 7073...@compuserve.com
-----------------------------------------


Garen Parham

unread,
Sep 23, 2000, 3:00:00 AM9/23/00
to

"Chris Torek" <to...@elf.bsdi.com> wrote in message
news:8qhm3m$3pg$1...@elf.bsdi.com...

>
> There is a terminology problem here: the C standards use the word
> "storage duration", not "storage class". (C89 lists two, but C99
> fixes a problem with C89, and lists three: static, automatic, and
> "allocated". Objects created by malloc() and destroyed by free()
> have "allocated duration" -- even in C89.)
>

The terminology the standard uses ("storage duration") doesn't seem much
different to me than "storage class", except that storage duration includes
more ("allocated"). Now that you mention it though, "storage duration"
seems better as the word ``duration'' says more about whats important about
the notion of being static (the lifetime of the object, within some scope).

>
> There is another problem with terminology here: someone who says
> "static variable" might mean *either* "variable declared using the
> static keyword" *or* "variable with static duration", and someone
> who says "external variable" might mean "variable declared using
> the extern keyword" *or* "variable with external linkage". So
> that makes four possible interpretations:
>
> variable with "static" keyword and "extern" keyword
> variable with "static" keyword and external linkage
> variable with static duration and "extern" keyword
> variable with static duration and external linkage

OK, I think what you're saying here is that the interpretation of "external
static variable" can vary (is potentially ambiguous). What I had tried to
point out though, is that there could be a valid interpretation. And that
the one I took seemed quite reasonable: I assumed the poster was referring
to a variable declared with the keyword extern, and which had static
duration which doesn't necessarily imply that the variable had to be
declared with the keyword static. e.g. global variables have static storage
class, but do not require the keyword static -- in that special case, the
keyword static applied to that global variable is used to indicate that it
is to have internal linkage.

I think the term "static storage class" captures that idea well. So when I
said:
``"Is an object declared with extern at global scope which inherits a
variable of static storage class not an "external static variable"''.

I meant to indicate that an object could be declared at global scope (file
scope) without the keyword static, and doing so also means it's storage
class is static (that the duration of it's life lasts until program
termination). And that because in the case of global variables, they do not
require the keyword static to have "static storage class", they still
inherit that property. My guess is that the standards chose the terminology
"static duration" because the term "static storage class" and the concept of
what static means is quite dependant on context.


[..snip..]


-Garen

Garen Parham

unread,
Sep 23, 2000, 3:00:00 AM9/23/00
to

"Richard Heathfield" <bin...@eton.powernet.co.uk> wrote in message
news:39CC6D45...@eton.powernet.co.uk...

> > extern int foo;
>
> AFAICT this is a file scope variable with external linkage. Is there
> some reason for thinking otherwise?

Since it is also a global variable, it is considered to have static storage
class (K&R2 A4.1). Or alternatively, as Chris Torek says the standard calls
it: to have static duration.

>
> The other side of the coin would be static int bar; - file scope
> variable with internal linkage. Perhaps we're violently agreeing? Not
> sure.
>

I was just trying to make a case that when the poster said "external static
variables", there is a valid interpretation - but you seemed to indicate
there wasn't with your reply "even if there were such a thing as an external
static variable.".

-Garen


Garen Parham

unread,
Sep 23, 2000, 3:00:00 AM9/23/00
to

"Kaz Kylheku" <k...@ashi.footprints.net> wrote in message
news:slrn8sqhv...@ashi.FootPrints.net...

>
> Storage class also encompasses concepts that are not related to storage
> duration. Consider that typedef is, syntactically, a storage class
specifier.

It's true that typedef is a storage class specifier, and it's usage does not
alter an objects storage duration, the same is true for extern (that does
seem weird). But the concept of a storage class still seems to remain the
same as storage duration to me. Am I missing something?


-Garen

Kaz Kylheku

unread,
Sep 23, 2000, 8:12:05 PM9/23/00
to
On Sat, 23 Sep 2000 15:51:20 -0700, Garen Parham <nos...@garen.net> wrote:
>The terminology the standard uses ("storage duration") doesn't seem much
>different to me than "storage class", except that storage duration includes
>more ("allocated").

Storage class also encompasses concepts that are not related to storage

Richard Heathfield

unread,
Sep 24, 2000, 3:00:00 AM9/24/00
to

I think, subconsciously, I was reading "external" as "extern". My
apologies.

There is no such thing as an extern static variable, that's for sure.

External static variables, Chris gives us to understand, are not the
same as extern static variables, and therefore they may well exist. :-)

Garen Parham

unread,
Sep 24, 2000, 3:00:00 AM9/24/00
to

"Richard Heathfield" <bin...@eton.powernet.co.uk> wrote in message
news:39CDC6AE...@eton.powernet.co.uk...
> Garen Parham wrote:

>
> I think, subconsciously, I was reading "external" as "extern". My
> apologies.

Me too! I was granting them a certain amount of assumptions. :)

>
> There is no such thing as an extern static variable, that's for sure.

Well, I don't think the phrase would appear in any standards documents. But
as I said before, with a few assumptions I'd take that to probably mean a
variable declared with the keyword extern, which has static storage class.

I think what I was (subconsciously! :)) trying to get at, is that I thought
you were trying to stick a bit too strictly there to your C standards
world-view of sorts, and throw out the posters statement of an "external
static variable" just because it did not fit that all that well into that
view - but that it still seemed clear what its meaning was. Anyhow, after
the fact it seems I was a minority in thinking that meaning was clear.
Whoops.

>
> External static variables, Chris gives us to understand, are not the
> same as extern static variables, and therefore they may well exist. :-)
>

Righto.

-Garen


Richard Heathfield

unread,
Sep 24, 2000, 3:00:00 AM9/24/00
to
Garen Parham wrote:
>
> "Richard Heathfield" <bin...@eton.powernet.co.uk> wrote in message
> news:39CDC6AE...@eton.powernet.co.uk...
> > Garen Parham wrote:
>
> >
> > I think, subconsciously, I was reading "external" as "extern". My
> > apologies.
>
> Me too! I was granting them a certain amount of assumptions. :)
>
> >
> > There is no such thing as an extern static variable, that's for sure.
>
> Well, I don't think the phrase would appear in any standards documents.

Well, that's because extern variables have external linkage, and static
variables have internal linkage, so

extern static int i;

means i's scope is **both** (a) everywhere in the program /and/ (b) only
in this translation unit. This is a contradiction, so by reductio ad
absurdum, such a declaration cannot be valid.

<snip>

> I think what I was (subconsciously! :)) trying to get at, is that I thought
> you were trying to stick a bit too strictly there to your C standards
> world-view of sorts, and throw out the posters statement of an "external
> static variable" just because it did not fit that all that well into that
> view - but that it still seemed clear what its meaning was.

If it had been clear, I probably wouldn't have misinterpreted it. :-)

> Anyhow, after
> the fact it seems I was a minority in thinking that meaning was clear.

I nearly failed to parse this. I think you're saying you now understand
why I was confused. I think.

> Whoops.

Right. :-)

Garen Parham

unread,
Sep 24, 2000, 3:00:00 AM9/24/00
to

"Garen Parham" <nos...@garen.net> wrote in message
news:uvdz5.1155$b47.4...@news.uswest.net...

>
> "Kaz Kylheku" <k...@ashi.footprints.net> wrote in message
> news:slrn8sqhv...@ashi.FootPrints.net...
>
>
> It's true that typedef is a storage class specifier, and it's usage does
not
> alter an objects storage duration, the same is true for extern (that does
> seem weird). But the concept of a storage class still seems to remain the
> same as storage duration to me. Am I missing something?
>
>

Argh. extern can effect an objects storage duration, scratch that part.
But typedef cannot. Which does make it particularly odd that it's grouped
in as a storage class specifier!

-Garen

Garen Parham

unread,
Sep 24, 2000, 3:00:00 AM9/24/00
to

"Richard Heathfield" <bin...@eton.powernet.co.uk> wrote in message
news:39CE0505...@eton.powernet.co.uk...

> Garen Parham wrote:
>
> Well, that's because extern variables have external linkage, and static
> variables have internal linkage, so

Oh no, brain overload. I assume by "extern variables" you mean ones whose
declarations involve using the keyword extern, and "static variables" ones
whose declarations involve using the keyword static? If not, I could take
the term "static variables" to mean variables that have static storage class
(standards: static duration), but in the case of global variables their
declarations do not have to involve using the static specifier to have this
property.

Also, variables declared with the keyword extern do not necessarily have
external linkage. Unfortunately I don't have any of the standards
documents, so my reference is from K&R2 in section A11.2 (Linkage):

"As discussed in $A10.2, the first external declaration for an identifier
gives the identifier internal linkage if the static specifier is used,
external linkage otherwise."

Where "external declaration" implies that the declaration involves the
keyword extern.

>
> extern static int i;
>
> means i's scope is **both** (a) everywhere in the program /and/ (b) only
> in this translation unit. This is a contradiction, so by reductio ad
> absurdum, such a declaration cannot be valid.
>
>

I was actually about to go for my logic text and look for this apparantly
new fallacy called reductio ad absurdum, then I realized it must be a silly
joke (it is, right? :)).

The example "extern static int i;" is not possible, but I don't think it
follows from your explanation above that. You stated: "extern variables
have external linkage".

Consider this example, which shows a variable declared with the keyword
extern that does not have external linkage:
void foo();
int main()
{
foo();
return 0;
}
static int i;
// Some time, in a land far-far away, comes the function foo():
void foo() // Using the double slash comments here intentionally.
{ // If it doesn't compile because your compiler doesn't support it by
default or you're using lotsa flags, you must be using a *real compiler*
// In that case I recommend that you upgrade to a *fake compiler*, used by
*fake programmers*! :)
extern int i; // You might do this if you know you want to use
'i', but don't want to mess with it's linkage.
}

-Garen

Kaz Kylheku

unread,
Sep 24, 2000, 3:00:00 AM9/24/00
to
On Sun, 24 Sep 2000 15:45:21 -0700, Garen Parham <nos...@garen.net> wrote:
>Argh. extern can effect an objects storage duration, scratch that part.
>But typedef cannot. Which does make it particularly odd that it's grouped
>in as a storage class specifier!

I think of it like this: typedef reserves translation-time storage for type
information which is bound to the declared name. A typedef may not be a
run-time object in the C program, but it is a real piece of information
that has to be stored somewhere for some duration.

Bruce G. Stewart

unread,
Sep 24, 2000, 8:18:39 PM9/24/00
to
Kaz Kylheku wrote:
>
> On Sun, 24 Sep 2000 15:45:21 -0700, Garen Parham <nos...@garen.net> wrote:
> >Argh. extern can effect an objects storage duration, scratch that part.
> >But typedef cannot. Which does make it particularly odd that it's grouped
> >in as a storage class specifier!
>
> I think of it like this: typedef reserves translation-time storage for type
> information which is bound to the declared name. A typedef may not be a
> run-time object in the C program, but it is a real piece of information
> that has to be stored somewhere for some duration.

Perhaps it's imaginary, so you'd need a complex version of & to get its
address.

Richard Heathfield

unread,
Sep 25, 2000, 2:00:52 AM9/25/00
to
Garen Parham wrote:
>
> "Richard Heathfield" <bin...@eton.powernet.co.uk> wrote in message
> news:39CE0505...@eton.powernet.co.uk...
> > Garen Parham wrote:
> >
> > Well, that's because extern variables have external linkage, and static
> > variables have internal linkage, so
>
> Oh no, brain overload. I assume by "extern variables" you mean ones whose
> declarations involve using the keyword extern, and "static variables" ones
> whose declarations involve using the keyword static?

Right. Sorry if my use of "extern" to represent "extern" and "static" to
represent "static" seems non-intuitive. ;-)

> If not, I could take
> the term "static variables" to mean variables that have static storage class
> (standards: static duration), but in the case of global variables their
> declarations do not have to involve using the static specifier to have this
> property.

What's a global variable? The Standard doesn't mention them.

>
> Also, variables declared with the keyword extern do not necessarily have
> external linkage.

Yes, they do.

> Unfortunately I don't have any of the standards
> documents, so my reference is from K&R2 in section A11.2 (Linkage):
>
> "As discussed in $A10.2, the first external declaration for an identifier
> gives the identifier internal linkage if the static specifier is used,
> external linkage otherwise."
>
> Where "external declaration" implies that the declaration involves the
> keyword extern.

Now you're making the same mistake I made. No, here, "external" simply
means "not in a function". Note that the absence of the word "static"
assures external linkage. The presence of the word "extern" also assures
external linkage. The presence of the word "static" assures internal
linkage. Therefore, the words "extern" and "static" can't be present in
the same declaration. (This is my understanding, at any rate, and I
think C99 breaks this cosy simplicity with static function parameters!,
but doesn't affect my fundamental argument about object types, AFAICT).

>
> >
> > extern static int i;
> >
> > means i's scope is **both** (a) everywhere in the program /and/ (b) only
> > in this translation unit. This is a contradiction, so by reductio ad
> > absurdum, such a declaration cannot be valid.
> >
> >
> I was actually about to go for my logic text and look for this apparantly
> new fallacy called reductio ad absurdum, then I realized it must be a silly
> joke (it is, right? :)).

"reductio ad absurdum: reduction to absurdity; the proof of a
proposition by proving the falsity of its contradictory..." - Chambers.
I'm just falling over myself with hysterical laughter - not.

>
> The example "extern static int i;" is not possible, but I don't think it
> follows from your explanation above that.

It does.

> You stated: "extern variables
> have external linkage".

They do.

>
> Consider this example, which shows a variable declared with the keyword
> extern that does not have external linkage:
> void foo();
> int main()
> {
> foo();
> return 0;
> }
> static int i;
> // Some time, in a land far-far away, comes the function foo():
> void foo() // Using the double slash comments here intentionally.
> { // If it doesn't compile because your compiler doesn't support it by
> default or you're using lotsa flags, you must be using a *real compiler*
> // In that case I recommend that you upgrade to a *fake compiler*, used by
> *fake programmers*! :)

Do you mean 'switch off the ISO compliance flags'?

> extern int i; // You might do this if you know you want to use
> 'i', but don't want to mess with it's linkage.

Hmm - maybe you have a point, and maybe you don't. Since I never use the
darn things if I can possibly avoid it, I haven't really boned up on
them. FWIW and IMHO, i still has external linkage; this is a
declaration, not a definition. i must still be present in some other
translation unit, again with external linkage. Perhaps it's time to
summon a wizard. Say with me, "One, two, three, ISO C, Who is right,
Garen or me?" ;-)

glen herrmannsfeldt

unread,
Sep 25, 2000, 3:00:00 AM9/25/00
to
to...@elf.bsdi.com (Chris Torek) writes:
(snip)

>There is another problem with terminology here: someone who says
>"static variable" might mean *either* "variable declared using the
>static keyword" *or* "variable with static duration", and someone
>who says "external variable" might mean "variable declared using
>the extern keyword" *or* "variable with external linkage". So
>that makes four possible interpretations:

> variable with "static" keyword and "extern" keyword
> variable with "static" keyword and external linkage
> variable with static duration and "extern" keyword
> variable with static duration and external linkage

If you used PL/I before C, then this is especially obvious, because
PL/I calls things what they are. There is no file score, but variables
can be either INTERNAL or EXTERNAL, where INTERNAL have procedure
scope and EXTERNAL have global scope. There are STATIC and AUTOMATIC
(those are PL/I keywords) which describe storage duration.

There are no AUTOMATIC EXTERNAL variables, and there is no file scope in PL/I.

The C use of the static and extern keywords is very strange.

>Of those four, at least one is an "impossible" combination: a
>variable declared with the "static" keyword can never have external
>linkage. (The only possibilities are internal linkage or no linkage.
>If an identifier appears with both internal and external linkage
>within a single translation unit, the behavior is undefined.)

Well, the examples were fine, but so long that I decided to snip them.

I think the point, that C's use of the keywords is confusing, has
been made.

PL/I programmers know what STATIC EXTERNAL means!

-- glen

Garen Parham

unread,
Sep 25, 2000, 3:00:00 AM9/25/00
to

"Richard Heathfield" <bin...@eton.powernet.co.uk> wrote in message
news:39CEEA14...@eton.powernet.co.uk...

> Garen Parham wrote:
> >
>
> Right. Sorry if my use of "extern" to represent "extern" and "static" to
> represent "static" seems non-intuitive. ;-)
>

Your use is the most intuitive I think, but there's a way to interpret it
which can make it untrue. This is a quirky thing in C.

> > If not, I could take
> > the term "static variables" to mean variables that have static storage
class
> > (standards: static duration), but in the case of global variables their
> > declarations do not have to involve using the static specifier to have
this
> > property.
>
> What's a global variable? The Standard doesn't mention them.

While not specifically mentioned, it's definition is alluded to in several
places. Here's a good one I use from K&R2 A4.1 ("Storage Class") pg 195:


"There are two storage classes: automatic and static." ...
"The objects declared outside all blocks, at the same level as function

definitions, are always static." (global objects)
This odd about this, is that global objectss have static storage class, but
their declarations don't have to involve the keyword static to make that so.
In this context, using the keyword static on a global object gives it
internal linkage.

I don't have the standard, so I can't check there. But Chris tells us that
they use the term "static duration" for global objects.

>
> >
> > Also, variables declared with the keyword extern do not necessarily have
> > external linkage.
>
> Yes, they do.

No, they don't. :) (Explanation at the bottom)

>
> Now you're making the same mistake I made. No, here, "external" simply
> means "not in a function". Note that the absence of the word "static"
> assures external linkage. The presence of the word "extern" also assures
> external linkage. The presence of the word "static" assures internal
> linkage. Therefore, the words "extern" and "static" can't be present in
> the same declaration. (This is my understanding, at any rate, and I
> think C99 breaks this cosy simplicity with static function parameters!,
> but doesn't affect my fundamental argument about object types, AFAICT).
>

We seem to have run into lots of trouble because each of us is interpreting
these two things differently. So I'm going to try not to say those words as
much and show you more code. I probably should have done that in the first
place. Chris had some good examples (see the 'v7' var), I'll try and
explain mine more and make it better.

>
> "reductio ad absurdum: reduction to absurdity; the proof of a
> proposition by proving the falsity of its contradictory..." - Chambers.
> I'm just falling over myself with hysterical laughter - not.
>

Hey, I hope you didn't take that as an insult - I'm just having fun here.

>
> Do you mean 'switch off the ISO compliance flags'?

Eh, not necessarily - mostly just trying to provide some comic relief about
Dan's reference to *real compilers*. :)

My example with more explanation this time.

Example A (from before):

// Assume foo() and main() are in the same translation unit for Example A


void foo();
int main()
{
foo();
return 0;
}

static int i; // Definition of global variable 'i' with internal linkage

/////////////////////////////////////

void foo()
{
extern int i; // Declaration of extern variable 'i' with internal
linkage, it's linkage properties are inherited from the definition
}

Example B:

void foo();
int main()
{
foo();
return 0;
}

int i; // Definition of global variable 'i' with external linkage and static
storage class

// Somewhere else, in another translation unit
void foo ()
{
extern int i; // Declaration of extern variable 'i' with external
linkage, here 'extern' is redundant, but offers some insurance.
}

Now, why would someone want to do anything like this? Well, lets say in
Example B this variable 'i' is calculated elsewhere in another translation
unit. Later on you change the structure of the program, eliminate some
dependancy or whatever - and now you can move the definition for foo() into
the same translation unit. Now, foo() still gets to have access to 'i' but
doesn't have to worry this change in linkage. Also, 'i' always has static
storage class as it's definition exists outside of all blocks, and in
Example A 'i' declared with extern in foo() has internal linkage and in
Example B, the opposite.

-Garen

Richard Heathfield

unread,
Sep 27, 2000, 2:23:44 AM9/27/00
to
Garen Parham wrote:
>
> "Richard Heathfield" <bin...@eton.powernet.co.uk> wrote in message
> news:39CEEA14...@eton.powernet.co.uk...

> > Garen Parham wrote:
> > >
> >
> > Right. Sorry if my use of "extern" to represent "extern" and "static" to
> > represent "static" seems non-intuitive. ;-)
> >
>
> Your use is the most intuitive I think, but there's a way to interpret it
> which can make it untrue. This is a quirky thing in C.

You're saying that on some occasions, "extern" doesn't mean "extern",
and "static" doesn't mean "static"?

>
> > > If not, I could take
> > > the term "static variables" to mean variables that have static storage
> class
> > > (standards: static duration), but in the case of global variables their
> > > declarations do not have to involve using the static specifier to have
> this
> > > property.
> >
> > What's a global variable? The Standard doesn't mention them.
>

> While not specifically mentioned, it's definition is alluded to in several
> places. Here's a good one I use from K&R2 A4.1 ("Storage Class") pg 195:
> "There are two storage classes: automatic and static." ...
> "The objects declared outside all blocks, at the same level as function
> definitions, are always static." (global objects)

(a) I didn't find the word "global" anywhere on that page, and
(b) K&R isn't the Standard, so it wouldn't have mattered if I had.

> This odd about this, is that global objectss have static storage class, but
> their declarations don't have to involve the keyword static to make that so.

You are defining a new term, "global objects" (the Standard doesn't
define this term, K&R don't use this term, and (as far as I can tell)
this term is not in common use in comp.lang.c, so I presume you're
defining it). Do we /need/ a new term? AFAICT we don't. It seems to me
that K&R, and the Standard, go to some lengths to /avoid/ the term,
possibly for the very reason that nobody really knows what it means.

> In this context, using the keyword static on a global object gives it
> internal linkage.

In what context would using the keyword static give it /ex/ternal
linkage, then?

>
> I don't have the standard, so I can't check there. But Chris tells us that
> they use the term "static duration" for global objects.

The Standard doesn't mention "global objects".

>
> >
> > >
> > > Also, variables declared with the keyword extern do not necessarily have
> > > external linkage.
> >
> > Yes, they do.

> No, they don't. :) (Explanation at the bottom)

Yes, they do. :-D

>
> >
> > Now you're making the same mistake I made. No, here, "external" simply
> > means "not in a function". Note that the absence of the word "static"
> > assures external linkage. The presence of the word "extern" also assures
> > external linkage. The presence of the word "static" assures internal
> > linkage. Therefore, the words "extern" and "static" can't be present in
> > the same declaration. (This is my understanding, at any rate, and I
> > think C99 breaks this cosy simplicity with static function parameters!,
> > but doesn't affect my fundamental argument about object types, AFAICT).
> >
>

> We seem to have run into lots of trouble because each of us is interpreting
> these two things differently.

Right. I have to say that your use of the word "global" obfuscates your
point of view, rather than clarifying it...

> So I'm going to try not to say those words as
> much

Too late! :-)

> and show you more code. I probably should have done that in the first
> place. Chris had some good examples (see the 'v7' var), I'll try and
> explain mine more and make it better.
>

<snip>

> My example with more explanation this time.
>
> Example A (from before):
>
> // Assume foo() and main() are in the same translation unit for Example A

> void foo();
> int main()
> {
> foo();
> return 0;
> }

> static int i; // Definition of global variable 'i' with internal linkage
>
> /////////////////////////////////////
>
> void foo()
> {
> extern int i; // Declaration of extern variable 'i' with internal
> linkage, it's linkage properties are inherited from the definition
> }

This is what I'm having problems with. The way I see it:

(a) the code has rather foolish namespace clashes between the inner i
and the outer i
(b) the code uses an extern object (yes, it /does/), which is generally
a bad idea
(c) the extern declaration refers to some external integer, not the
static int i within this source
(d) I'm not even sure if what you've written is legal, but it's
certainly unwise
(e) despite what you say, IMHO i does not have internal linkage; it's an
extern variable, so it has external linkage.

Clearly you disagree with (e). So, can you prove it? Where in the
Standard does it explain that extern objects have external linkage
unless they are declared (note, declared, not defined) at function scope
and also have a name clash with file scope variables with internal
linkage? I can't find such a clause anywhere. This may be because I
don't know the Standard well enough, of course.

>
> Example B:


>
> void foo();
> int main()
> {
> foo();
> return 0;
> }

> int i; // Definition of global variable 'i' with external linkage and static
> storage class

Definition of variable 'i' with file scope and external linkage.

>
> // Somewhere else, in another translation unit
> void foo ()
> {
> extern int i; // Declaration of extern variable 'i' with external
> linkage, here 'extern' is redundant, but offers some insurance.

No, it's not redundant. If you left it out, it would be a local variable
within foo().

> }
>
> Now, why would someone want to do anything like this?

This is the most important question you've raised about this code.
(/Your/ code, remember...) ;-)

> Well, lets say in
> Example B this variable 'i' is calculated elsewhere in another translation
> unit. Later on you change the structure of the program, eliminate some
> dependancy or whatever - and now you can move the definition for foo() into
> the same translation unit. Now, foo() still gets to have access to 'i' but
> doesn't have to worry this change in linkage. Also, 'i' always has static
> storage class as it's definition exists outside of all blocks, and in
> Example A 'i' declared with extern in foo() has internal linkage and in
> Example B, the opposite.

This seems to be an explanation of how to complexify code maintenance.
If you avoid external linkage altogether (for objects, not functions of
course), you don't run into this problem. If you can avoid file scope
altogether (for objects again), you have even fewer problems.

Garen Parham

unread,
Sep 27, 2000, 3:00:00 AM9/27/00
to

"Richard Heathfield" <bin...@eton.powernet.co.uk> wrote in message news:39D19270...@eton.powernet.co.uk...

> Garen Parham wrote:
>
>
> (a) I didn't find the word "global" anywhere on that page, and
> (b) K&R isn't the Standard, so it wouldn't have mattered if I had.
>

Yeah, there isn't an official definition for it, but since I had referred to it before, I thought I'd define it so I could use the
word without having to mention the definition over again.

>
> This is what I'm having problems with. The way I see it:
>
> (a) the code has rather foolish namespace clashes between the inner i
> and the outer i
> (b) the code uses an extern object (yes, it /does/), which is generally
> a bad idea
> (c) the extern declaration refers to some external integer, not the
> static int i within this source
> (d) I'm not even sure if what you've written is legal, but it's
> certainly unwise
> (e) despite what you say, IMHO i does not have internal linkage; it's an
> extern variable, so it has external linkage.

Regarding (a) and (b), I would agree that using such a method is probably questionable. The example was mainly something I made up
for illustration. for (d) yes it's legal, yes probably unwise. For (c) and (e):

From N869 6.2.2 Linkage and identifiers:

[#4] For an identifier declared with the storage-class
specifier extern in a scope in which a prior declaration of
that identifier is visible,21) if the prior declaration
specifies internal or external linkage, the linkage of the
identifier at the later declaration is the same as the
linkage specified at the prior declaration. If no prior
declaration is visible, or if the prior declaration
specifies no linkage, then the identifier has external
linkage.

I'm told that this particular part is identical in C99 as well. Also, it coincides equivalently (so far as I can tell ) with the
K&R2 appendix quote, and this summary posted earlier from Chris Torek:

.... <cut section>


The "extern" keyword is even more bizarre. Its effect depends on
whether there is a declaration of the same variable in scope yet.
If there *is* a visible declaration, "extern" refers back to its
linkage; if not, "extern" gives the variable external linkage

... </cut section>


>
> No, it's not redundant. If you left it out, it would be a local variable
> within foo().

Right, I assumed that foo() wanted to use the 'i' at file scope.

> This seems to be an explanation of how to complexify code maintenance.
> If you avoid external linkage altogether (for objects, not functions of
> course), you don't run into this problem. If you can avoid file scope
> altogether (for objects again), you have even fewer problems.
>
>

Probably why I think I've never actually seen it used. :) Also, the dangerous thing is that (N869 6.2.2):

[#7] If, within a translation unit, the same identifier
appears with both internal and external linkage, the
behavior is undefined.


-Garen

Chris Torek

unread,
Sep 27, 2000, 3:00:00 AM9/27/00
to
[Regarding a translation unit containing something like this:]

>> static int i; // Definition of global variable 'i' with internal linkage
>> void foo() {
>> extern int i; // Declaration of extern variable 'i' with internal
>> linkage, it's linkage properties are inherited from the definition
>> }

In article <39D19270...@eton.powernet.co.uk>


Richard Heathfield <bin...@eton.powernet.co.uk> wrote:
>This is what I'm having problems with. The way I see it:
>
>(a) the code has rather foolish namespace clashes between the inner i
>and the outer i

The code actually has only one variable "i". The first line:

static int i; /* at file scope */

declares an object of type "int", static duration, and internal
linkage using the name "i". Any other declaration of the identifier
"i" that has internal linkage will refer to this same "i". (This
declaration is also a "tenative definition", and will no doubt end
up defining "i" by the end of the translation unit, as if we had
written:

static int i = 0; /* at file scope */

but this is a separate issue.)

>(b) the code uses an extern object (yes, it /does/), which is generally
>a bad idea

If you mean "declarations using the extern keyword, but appearing
within a scope narrower than file scope, is generally a bad idea,"
I would agree with that.

>(c) the extern declaration refers to some external integer, not the
>static int i within this source

Ah, this is wrong; see, e.g., N2620 section 6.1.2.2, paragraph 4:

[#4] For an identifier declared with the storage-class
specifier extern in a scope in which a prior declaration of

that identifier is visible, if the prior declaration


specifies internal or external linkage, the linkage of the

identifier at the later declaration becomes the linkage


specified at the prior declaration. If no prior declaration
is visible, or if the prior declaration specifies no
linkage, then the identifier has external linkage.

>(d) I'm not even sure if what you've written is legal, but it's
>certainly unwise

It *is* legal, and it is horrendously confusing. The C standards
have to say *something* about what happens in this case, since the
case itself can exist. I am not sure that what the C standards
*do* say is the "best thing", but it is what they say, and it is
not impossible to live with.

>> Example B [contains]


>> int i; // Definition of global variable 'i' with external linkage and static
>> storage class

>Definition of variable 'i' with file scope and external linkage.

Well, neither really: this is only a *tenative* definition, not
a "definite definition" (as it were). But yes, the identifier "i"
has file scope and external linkage.

>> // Somewhere else, in another translation unit
>> void foo ()
>> {
>> extern int i; // Declaration of extern variable 'i' with external
>> linkage, here 'extern' is redundant, but offers some insurance.

>No, it's not redundant. If you left it out, it would be a local variable
>within foo().

Right.

I claim it would be "better" (in some sense) to write:

extern int i;
void foo(void) {
...
}

so that "i" again has file scope; I think people find this less
confusing. Moreover, placing the declaration for "i" inside function
foo() restricts its scope:

void foo(void) {
extern int i;
...
}
/* identifier "i" is now out of scope */

but not, in some sense, usefully. The only thing that putting "i"
out-of-scope accomplishes is to produce an error if we attempt to
refer to it again later:

void foo2(void) {
use(i); /* error */
}

If we then declare or define "i" again later, this is either
redundant -- a bad thing when it comes to maintainin the code later --
or an outright error. Worse, as an error, it is one that need never
be diagnosed:

static double i;

Now we have the same identifier declared with both internal and
external linkage (=> undefined behavior), and given two conflicting
types (int and double => undefined behavior). The latter would at
least provoke a diagnostic, had we declared "i" at file scope
before.

(Incidentally, note that "better" != "best", nor even necessarily
"good". :-) Unlike some other programmers, I do not feel that all
"global variables" -- whatever we may mean by that :-) -- are
*automatically* bad or "evil", but they should certainly be used
with caution.)

Garen Parham

unread,
Sep 27, 2000, 3:00:00 AM9/27/00
to

"Chris Torek" <to...@elf.bsdi.com> wrote in message news:8qsehd$f39$1...@elf.bsdi.com...

> [Regarding a translation unit containing something like this:]
>
> [#4] For an identifier declared with the storage-class
> specifier extern in a scope in which a prior declaration of
> that identifier is visible, if the prior declaration
> specifies internal or external linkage, the linkage of the
> identifier at the later declaration becomes the linkage
> specified at the prior declaration. If no prior declaration
> is visible, or if the prior declaration specifies no
> linkage, then the identifier has external linkage.
>

Wow. I posted this same quote. And my news server says we posted at precisely the same time too, 2:17AM PST. Spooky. As spooky
as static and extern. :)

-Garen


Garen Parham

unread,
Sep 27, 2000, 3:00:00 AM9/27/00
to

"Garen Parham" <nos...@garen.net> wrote in message news:_djA5.5$q9....@news.uswest.net...

>
>
> Wow. I posted this same quote. And my news server says we posted at precisely the same time too, 2:17AM PST. Spooky. As spooky
> as static and extern. :)
>
> -Garen
>

Nevermind. This thread is so deep I can no longer read. 2:17 < 2:27.

-Garen

Lawrence Kirby

unread,
Sep 27, 2000, 3:00:00 AM9/27/00
to
In article <5Bvz5.1065$wi1.3...@news.uswest.net>
nos...@garen.net "Garen Parham" writes:

...

>Argh. extern can effect an objects storage duration, scratch that part.
>But typedef cannot.

Let's see

int i;

Here i could have static or automatic storage duration

typedef int i;

Here i has no storage duration at all (due to the fact that it no longer
names an object). Seems a fairly ultimate effect on storage duration to
me. :-)

> Which does make it particularly odd that it's grouped
>in as a storage class specifier!

You could think of it as a storage class specifier that specifies
"no storage" i.e. it just carries the type around.

Garen Parham

unread,
Sep 27, 2000, 3:00:00 AM9/27/00
to

"Lawrence Kirby" <fr...@genesis.demon.co.uk> wrote in message news:970063...@genesis.demon.co.uk...

>
> Let's see
>
> int i;
>
> Here i could have static or automatic storage duration
>
> typedef int i;
>
> Here i has no storage duration at all (due to the fact that it no longer
> names an object). Seems a fairly ultimate effect on storage duration to
> me. :-)

I see what you mean. :)

>
> > Which does make it particularly odd that it's grouped
> >in as a storage class specifier!
>
> You could think of it as a storage class specifier that specifies
> "no storage" i.e. it just carries the type around.
>

Yeah, thats just it I think -- I "could" think of it that way (I thought of it a bit differently before). Thats probably pretty
much the line of thinking that got it to be included as a "storage class specifier" then. Thanks for that tidbit. :)

-Garen


Richard Heathfield

unread,
Sep 29, 2000, 3:00:00 AM9/29/00
to
Chris Torek wrote:
>
> [Regarding a translation unit containing something like this:]
> >> static int i; // Definition of global variable 'i' with internal linkage
> >> void foo() {
> >> extern int i; // Declaration of extern variable 'i' with internal
> >> linkage, it's linkage properties are inherited from the definition
> >> }
>
> In article <39D19270...@eton.powernet.co.uk>
> Richard Heathfield <bin...@eton.powernet.co.uk> wrote:
> >This is what I'm having problems with. The way I see it:
> >
> >(a) the code has rather foolish namespace clashes between the inner i
> >and the outer i
>
> The code actually has only one variable "i".

Hmm. Bad sign.

/me steels himself in preparation for a thorough beating...

> The first line:
>
> static int i; /* at file scope */
>
> declares an object of type "int", static duration, and internal
> linkage using the name "i". Any other declaration of the identifier
> "i" that has internal linkage will refer to this same "i". (This
> declaration is also a "tenative definition", and will no doubt end
> up defining "i" by the end of the translation unit, as if we had
> written:
>
> static int i = 0; /* at file scope */
>
> but this is a separate issue.)

Okay... ouch.

>
> >(b) the code uses an extern object (yes, it /does/), which is generally
> >a bad idea
>

> If you mean "declarations using the extern keyword, but appearing
> within a scope narrower than file scope, is generally a bad idea,"
> I would agree with that.

I'd actually go further than that, in my pseudofascist way, and say that
defining file scope variables is a bad idea, and defining file scope
variables with external linkage is worse. (Some, we're stuck with - e.g.
errno may (but does not have to) be a file scope variable with external
linkage... I'm not advocating that we should eschew variables (or - er -
"pseudo-variables") defined by the Standard.)

Still, your caveat makes me think you may not agree with me as much as
you thought you did, so ouch again.

>
> >(c) the extern declaration refers to some external integer, not the
> >static int i within this source
>

> Ah, this is wrong;

<snip Standard quote>

OUch with a capital OU.

/me is on the ropes...

>
> >(d) I'm not even sure if what you've written is legal, but it's
> >certainly unwise
>

> It *is* legal, and it is horrendously confusing. The C standards
> have to say *something* about what happens in this case, since the
> case itself can exist. I am not sure that what the C standards
> *do* say is the "best thing", but it is what they say, and it is
> not impossible to live with.

I agree with you that it is horrendously confusing. I will even accept
that it is legal. I am not convinced that it's useful.

>
> >> Example B [contains]


> >> int i; // Definition of global variable 'i' with external linkage and static
> >> storage class
>
> >Definition of variable 'i' with file scope and external linkage.
>

> Well, neither really: this is only a *tenative* definition, not

> a "definite definition" (as it were). But yes, the identifier "i"
> has file scope and external linkage.

Could I salvage a smidgen of pride by pointing out your typo? No? Ah, I
thought not...

>
> >> // Somewhere else, in another translation unit
> >> void foo ()
> >> {
> >> extern int i; // Declaration of extern variable 'i' with external
> >> linkage, here 'extern' is redundant, but offers some insurance.
>
> >No, it's not redundant. If you left it out, it would be a local variable
> >within foo().
>

> Right.

Yay! :-)

>
> I claim it would be "better" (in some sense) to write:
>
> extern int i;
> void foo(void) {
> ...
> }
>
> so that "i" again has file scope; I think people find this less
> confusing.

Better still would be to re-design the program altogether. For example:

void foo(int *pointer_to_i)
{
/* ... */
}

Moreover, placing the declaration for "i" inside function
> foo() restricts its scope:
>
> void foo(void) {
> extern int i;
> ...
> }
> /* identifier "i" is now out of scope */
>
> but not, in some sense, usefully. The only thing that putting "i"
> out-of-scope accomplishes is to produce an error if we attempt to
> refer to it again later:
>
> void foo2(void) {
> use(i); /* error */
> }

Why is this an error? Surely by now we've established that there is a
file scope variable called i to which this line could legitimately
refer?

<snip more scary stuff>


>
> (Incidentally, note that "better" != "best", nor even necessarily
> "good". :-) Unlike some other programmers, I do not feel that all
> "global variables" -- whatever we may mean by that :-) -- are
> *automatically* bad or "evil", but they should certainly be used
> with caution.)

FWIW, my opinion is that we should avoid them, like goto, at all costs
during the early stage of our careers; when we are expert enough to use
them properly, then let us by all means do that.

I don't expect I'll ever be expert enough to feel *comfortable* with
file scope variables with external linkage - although, of course, I have
to deal with them frequently on client sites. Fortunately, I've never
encountered anything quite so obfuscatory as Garen's example.

And now, for tradition's sake:

Garen - my apologies for my erroneous reply to you.
Chris - thanks for the correction.

Garen Parham

unread,
Sep 30, 2000, 3:00:00 AM9/30/00
to

"Richard Heathfield" <bin...@eton.powernet.co.uk> wrote in message news:39D502A1...@eton.powernet.co.uk...

>
> I'd actually go further than that, in my pseudofascist way, and say that
> defining file scope variables is a bad idea, and defining file scope
> variables with external linkage is worse. (Some, we're stuck with - e.g.
> errno may (but does not have to) be a file scope variable with external
> linkage... I'm not advocating that we should eschew variables (or - er -
> "pseudo-variables") defined by the Standard.)

A good rule to follow until you know better.

> >
> > >> // Somewhere else, in another translation unit
> > >> void foo ()
> > >> {
> > >> extern int i; // Declaration of extern variable 'i' with external
> > >> linkage, here 'extern' is redundant, but offers some insurance.
> >
> > >No, it's not redundant. If you left it out, it would be a local variable
> > >within foo().
> >
> > Right.
>
> Yay! :-)

I figured using it within function scope would be a good idea, since in that example I was trying to come up with a plausible
explanation for why anyone would want to do something that weird. That line of thinking is of course not good. :)

>
> Moreover, placing the declaration for "i" inside function
> > foo() restricts its scope:
> >
> > void foo(void) {
> > extern int i;
> > ...
> > }
> > /* identifier "i" is now out of scope */
> >
> > but not, in some sense, usefully. The only thing that putting "i"
> > out-of-scope accomplishes is to produce an error if we attempt to
> > refer to it again later:
> >
> > void foo2(void) {
> > use(i); /* error */
> > }
>
> Why is this an error? Surely by now we've established that there is a
> file scope variable called i to which this line could legitimately
> refer?

In my example the declaration and definition were in the same translation unit, but this seems to be a hypothetical example of what
would happen where they're not.

> I don't expect I'll ever be expert enough to feel *comfortable* with
> file scope variables with external linkage - although, of course, I have
> to deal with them frequently on client sites. Fortunately, I've never
> encountered anything quite so obfuscatory as Garen's example.
>
> And now, for tradition's sake:
>
> Garen - my apologies for my erroneous reply to you.
> Chris - thanks for the correction.
>
>

I haven't been around here long enough to take notice to any traditions, but you need not apologize. We ought to be more concerned
with /what/ is correct and not so much with /who/ is (IMHO). I hope the original poster didn't follow this thread and get very
confused, frustrated, and do something rash like swear off C altogether or something. :)

-Garen


Chris Torek

unread,
Sep 30, 2000, 3:00:00 AM9/30/00
to
I am removing a lot of context here, but (I hope) not *too* much...

In article <39D502A1...@eton.powernet.co.uk>,


Richard Heathfield <bin...@eton.powernet.co.uk> wrote:
>Could I salvage a smidgen of pride by pointing out your typo? No? Ah, I
>thought not...

(which typo was that? :-) )

I wrote, in part (on variable scopes and linkages):
>>Moreover, placing [an external-linkage] declaration for "i" inside


>>function foo() restricts its scope:
>>
>> void foo(void) {
>> extern int i;
>> ...
>> }
>> /* identifier "i" is now out of scope */
>>
>> but not, in some sense, usefully. The only thing that putting "i"
>> out-of-scope accomplishes is to produce an error if we attempt to
>> refer to it again later:
>>
>> void foo2(void) {
>> use(i); /* error */
>> }

>Why is this an error? Surely by now we've established that there is a
>file scope variable called i to which this line could legitimately
>refer?

I meant "in some hypothetical other translation unit". That is, if
an entire source file were, say:

/* badexample.c */
extern void use(int);
void f(void) { extern int i; use(i); }
void g(void) { use(i); } /* error */

you must get a diagnostic based on the "use(i)" call in g(): there is
no identifier "i" in scope here.

The reason this is not very "useful" is that, in order to use the
*same* variable "i" ever again, you have to re-declare it. You
could replace the definition of function g() above with:

void g(void) { extern int i; use(i); }

(making g() identical to f()). If you want to get a *different*
"global" variable named "i", you are *really* out of luck, because
there is no such thing.

By "global" here, I mean something other than a variable truly
local to some particular function. In ANSI/ISO terms, I mean an
"i" with "no linkage". That is:

void example3(void) { int i; ... }
void example4(void) { static int i; ... }

are okay -- these two "int i"s have no linkage -- but this is not:

static char *i;
void example5(void) { i = "hello"; }

This "i" has internal linkage. Since "badexample.c" already had a
declaration of "i" with external linkage -- the one inside the
definition of "f" -- we run into the dreaded "undefined behavior".
This particular undefined behavior does not have to be diagnosed,
and if "badexample2.c" consists entirely of, say:

/* badexample2.c */
extern void use(int);
void f(void) { extern int i; use(i); }
static char *i; /* error */
void g(void) { i = "hello"; }

no C compiler ever *has* to point out that this code is undefined
and probably does not do what you wanted. GCC, quite cleverly,
*does* complain:

stdin:3: warning: `i' was declared `extern' and later `static'

which is nice, since on most (all?) Unix-like systems, badexample2.c
indeed does something other than what the programmer probably wanted.

>FWIW, my opinion is that we should avoid ["global variables", i.e.,
>variables that, in C, have file scope and external linkage], like goto,


>at all costs during the early stage of our careers; when we are expert
>enough to use them properly, then let us by all means do that.

They are hard to get away from -- for instance, in some sense,
stdin, stdout, and stderr are just such "global variables". These
three "FILE *" things could in fact be functions:

FILE *__stdin(void);
FILE *__stdout(void);
FILE *__stderr(void);
#define stdin (__stdin())
#define stdout (__stdout())
#define stderr (__stderr())

but they *act* a lot like variables that you never change, and
in quite a few implementations, they are actually defined as
something like:

extern FILE __stdin, __stdout, __stderr;
#define stdin (&__stdin)
#define stdout (&__stdout)
#define stderr (&__stderr)

or:

extern FILE __sF[];
#define stdin (&__sF[0])
#define stdout (&__sF[1])
#define stderr (&__sF[2])

or some such. (4.4BSD used to use the latter; in BSD/OS, we changed
it to the former so that we could add new fields to a "FILE" object.)

If standard I/O streams are not too scary, perhaps one rule that might
work is: "any variable that might be set once at program startup, but
never changes after that, and is used throughout the program, is a
candidate to be made a global variable."

>I don't expect I'll ever be expert enough to feel *comfortable* with
>file scope variables with external linkage - although, of course, I have
>to deal with them frequently on client sites.

My own rule is even more relaxed than the one above. It boils down
to: "if there is something that *looks* like a variable, the problem
absolutely guarantees that there is only *one* such thing, and the
variable-like object or value is needed throughout the entire
solution, go ahead and make it a global variable." That means
that, for instance, "the place where all the normal output goes"
-- not necessarily stdout, if the problem calls for being able to
redirect its output in something other than the traditional Unix-like
method -- might be a global "FILE *outfp;".

The trick is, you have to be pretty sure about all these conditions,
and even then, you have to be prepared to have the problem
specification change on you. The better you can pin down the
problem, the easier it is to use a global variable. The "config"
program in BSD/OS has a rather large set (some of which probably
should be collected up in a "struct"):
---------------------
const char *conffile; /* source file, e.g., "GENERIC.sparc" */
const char *confdirbase; /* basename of compile directory, usu. same */
const char *machine; /* machine type, e.g., "sparc" */
int errors; /* counts calls to error() */
int minmaxusers; /* minimum "maxusers" parameter */
int defmaxusers; /* default "maxusers" parameter */
int maxmaxusers; /* maximum "maxusers" parameter */
int maxusers; /* configuration's "maxusers" parameter */
int ktimezone; /* configuration's timezone (i386 only) */
struct nvlist *options; /* options */
struct nvlist *mkoptions; /* makeoptions */
struct hashtab *devbasetab; /* devbase lookup */
struct hashtab *selecttab; /* selects things that are "optional foo" */
struct hashtab *needcnttab; /* retains names marked "needs-count" */

struct devbase *allbases; /* list of all devbase structures */
struct config *allcf; /* list of configured kernels */
struct devi *alldevi; /* list of all instances */
struct devi *allpseudo; /* list of all pseudo-devices */
int ndevi; /* number of devi's (before packing) */
int npseudo; /* number of pseudo's */

struct files *allfiles; /* list of all kernel source files */

struct devi **packed; /* arrayified table for packed devi's */
int npacked; /* size of packed table, <= ndevi */
---------------------
(This program builds a kernel "compile" directory from a kernel-
configuration file. The configuration file allows one to build a
"stripped-down" operating system for small machines, for instance,
so that you can build a BSD/OS system that omits the support for
various file systems. Other OSes solve similar problems via
"loadable" drivers and file systems, but that too is a compromise:
that requires having the loading code in the kernel, or at least
in the boot loader. This is the same old delayed-binding problem
that comes up repeatedly in computing. The earlier you do your
binding, the easier it is to get an "optimized" solution, but the
less flexible it is. "config" intermediates: it provides the
flexibility we want, and does the binding *before* we compile
a kernel.)

Chris Torek

unread,
Oct 1, 2000, 3:00:00 AM10/1/00
to
In article <8r4qvr$o9l$1...@elf.bsdi.com> I wrote, in part:

>By "global" here, I mean something other than a variable truly
>local to some particular function. In ANSI/ISO terms, I mean an
>"i" with "no linkage".

That should read:

an "i" with something OTHER THAN "no linkage"

(which leaves only internal and external linkage).

I hope that, by giving examples of what is defined and what is not,
I did not confuse everyone too much. :-)

By the way, I am suggesting that there are two likely meanings for
the phrase "global variable", when dealing with C code: a file-scope
variable with internal linkage, or a file-scope variable with
external linkage. More generally, though, *any* variable with
*any* linkage could be considered "global". This is a case where
being precise can pay off. Joe might say: "I have a global variable
xyz ..." and Bob might hear, in effect: "I have a variable named
xyz with file scope and external linkage". If Joe meant "with file
scope and *internal* linkage", Bob might have trouble using Joe's
code.

For "identifiers", there are three bits of information you need to
know: scope, name space, and linkage. If the identifier refers to
an ordinary variable, there are two more pieces of information you
need to know: its type, and its storage duration. The "name space"
part drops out (all variables are in the "ordinary" name space),
so you have four things to keep in mind -- scope, linkage, type,
and storage duration -- and as long you know all of those, you can
be certain of what you are doing with that variable.

Reply all
Reply to author
Forward
0 new messages