Array definition guarantees

M

mdh

May I ask.

If an array is defined , not as a static, but outside of a function,
is there any guarantee as to the contents of each element?

Thanks.
 
S

s0suk3

May I ask.

If an array is defined , not as a static, but outside of a function,
is there any guarantee as to the contents of each element?

A variable (of any kind, including an array) declared outside a
function always has static storage duration, and declaring such a
variable with the 'static' storage class makes it have internal
linkage. So yes, an array declared outside a function is guaranteed
have all its elements set to zero.

Sebastian
 
M

mdh

A variable (of any kind, including an array) declared outside a
function always has static storage duration, and declaring such a
variable with the 'static' storage class makes it have internal
linkage. So yes, an array declared outside a function is guaranteed
have all its elements set to zero.


So,just to be sure, the only difference in using the actual word
'static' in the declaration/definition is the scope of that variable?
 
M

mdh

in comp.lang.c:



So your array defined at file scope, outside of a function, is
guaranteed to be zero-initialized.

--


Jack, thank you for that very nice explanation.
 
S

s0suk3

So,just to be sure,  the only difference in using the actual word
'static' in the declaration/definition is the scope of that variable?


A declaration *inside* a function with the 'static' storage class
makes the variable have static storage duration (i.e., it retains it's
value from program startup until program termination).

A declaration *outside* a function with the 'static' storage class,
however, has a different meaning: it makes it have "internal
linkage" (i.e., the variable/function is visible throughout file where
it's declared, but not in other files), as opposed to "external
linkage" (i.e., the variable/function is visible to all the files in
the program), which is the default for variables/functions declared
outside any function.

The "scope" of a variable, which is what you mentioned, is something
different from "linkage." A variable can have "file scope" (i.e., it's
visible throughout the whole file where it's declared, and therefore
to all functions in the file), or "block scope" (i.e., it's declared
inside a function or inside a block inside the function, and therefore
it's visible only inside that block).

Sebastian
 
M

mdh

     The keyword `static' has multiple meanings depending
on the context in which it is used.

     Any array (or other variable) defined outside a function
has "static storage duration,"

snip

.
The `static' keyword in this case .. control(s)..... the linkage:

     Inside a function, `static' has a different meaning.  Any
variable not declared as `extern' has no linkage at all; it is
"visible within its block" and nowhere else.




Eric, I did not realize one has to explicitly declare a variable
**inside** a function with the word "extern" to confer external
linkage.
So, one can therefore use this syntax, although not sure why one
would?

extern static char a; to mean

char a has external linkage &
char a has static duration, as defined above by you.


Thank you very much.
 
M

mdh

     Yes: Without `extern', a variable inside a block has
no linkage at all.




     No: You can't have both `extern' and `static' in the
same declaration.  Nor can you combine `extern' and `auto'
or `static' and `register' or `auto' and `typedef': One
specifier is the limit.


ok...Eric...I think I get it...I've probably given you enough laughs
for the evening !!!! :)

     A variable declared `extern' is not a definition, but
a "link" to an actual variable defined somewhere else.....

That was my initial understanding as well. I think I see the other
implications more clearly, so thank you for that explanation.
 
M

mdh

A declaration *inside* a function with the 'static' storage class
makes the variable have static storage duration (i.e., it retains it's
value from program startup until program termination).

A declaration *outside* a function with the 'static' storage class,
however, has a different meaning: it makes it have "internal
linkage" (i.e., the variable/function is visible throughout file where
it's declared, but not in other files), as opposed to "external
linkage" (i.e., the variable/function is visible to all the files in
the program), which is the default for variables/functions declared
outside any function.

The "scope" of a variable, which is what you mentioned, is something
different from "linkage." A variable can have "file scope" (i.e., it's
visible throughout the whole file where it's declared, and therefore
to all functions in the file), or "block scope" (i.e., it's declared
inside a function or inside a block inside the function, and therefore
it's visible only inside that block).

Sebastian

Thank you Sebastian
 
M

mdh

The "scope" of a variable, which is what you mentioned, is something
different from "linkage."


Does this then summarize the differences between scope and linkage
as you then explained?

Linkage:

The relationship of translation units to each other in terms of
visibility.
The word "external" implies that an object *might* be seen by another
translation unit, provided the correct declaration is used in that t.
u.
The word "internal" implies that the object will never be seen by
another t.u, only be seen within the t.u where the object is defined.


Scope:

The relationship of namespace to the **position** of the declaration
within a single tu., (using all the rules that are spelled out in K&R)

Lastly, I think that this also implies that an object defined as
having internal linkage over-rides the scope rules..well I hope so or
it is back to the drawing board.
 
J

James Kuyper

mdh wrote:
....
Does this then summarize the differences between scope and linkage
as you then explained?

Linkage:

The relationship of translation units to each other in terms of
visibility.
The word "external" implies that an object *might* be seen by another
translation unit, provided the correct declaration is used in that t.
u.
The word "internal" implies that the object will never be seen by
another t.u, only be seen within the t.u where the object is defined.

Nitpick: linkage, scope, and visibility refer to identifiers, not
objects. An object whose name has internal linkage can still be accessed
from a different translation unit, through a pointer. Identifiers with
linkage can identify functions, as well as objects.
Scope:

The relationship of namespace to the **position** of the declaration
within a single tu., (using all the rules that are spelled out in K&R)

Lastly, I think that this also implies that an object defined as
having internal linkage over-rides the scope rules..well I hope so or
it is back to the drawing board.

No, the scope rules still apply to objects with internal linkage. For
example, an identifier with internal linkage and file scope is in scope
from the point of declaration to the end of the translation unit. An
identifier with internal linkage and block scope is in scope from the
point of declaration to the end of the block. In both cases, the scope
would be exactly the same if it had external linkage.
 
M

mdh

No, the scope rules still apply to objects with internal linkage. For
example, an identifier with internal linkage and file scope is in scope
from the point of declaration to the end of the translation unit. An
identifier with internal linkage and block scope is in scope from the
point of declaration to the end of the block. In both cases, the scope
would be exactly the same if it had external linkage.


Thanks James.

So, in the end, the word "linkage" is used to govern the relationship
between translation units and identifiers ( as you answered, well, as
I **think** you answered) and the word "scope" refers to a single
translation unit and governs how identifiers are limited in their
namespace? Does that pretty much summarize it?
 
J

jameskuyper

mdh said:
Thanks James.

So, in the end, the word "linkage" is used to govern the relationship
between translation units and identifiers ( as you answered, well, as
I **think** you answered)

I can't take the credit for that; the best explanation of linkage you
recieved was given by Eris Sosman; I just helped you disentangle the
idea of linkage from the idea of scope.
... and the word "scope" refers to a single
translation unit and governs how identifiers are limited in their
namespace? Does that pretty much summarize it?

Yes, that covers the basic idea.
 
C

Chris Torek

So, in the end, the word "linkage" is used to govern the relationship
between translation units and identifiers ...

Right: linkage tells you where, within and between separate
translation units, the identifier will be "linked" to another
identifier that is spelled sufficiently similarly.
... and the word "scope" refers to a single translation unit
Yes...

and governs how identifiers are limited in their namespace?

I think it is closer to say that scope tells you where the name
can be "seen". There are only two "important" scopes: block and
file. (There are two more, "function scope" and "function prototype
scope". The former is strictly for goto-labels, and the latter is
a bit of a hack, being a substitute for block scope where there is
no brace-pair {...} to mark a block, but instead are just the
parentheses (...) that mark the function prototype. Function
prototype scope is thus really just "block scope in drag". Meanwhile,
"function scope" is really just "the outermost block of the containing
function" scope, and hence again is actually just a form of block
scope.)

An identifier that has file scope can be seen from whatever point
it is declared up to the end of the translation unit. An identifier
with block scope can be seen up until the block is closed. (As
noted above, a "function prototype" is closed by a closing parenthesis,
and the "function scope" for a goto label is closed by the closing
brace that ends the function body. So these identifiers' scopes
end in exactly the same way as block-scope identifiers.)

There is a connection -- exactly how deep or strong can be debated
-- between the concepts, as an identifier with block scope (or the
pseudo-block-scope that you get with function and function-prototype
scopes) normally has "no linkage". In order to obtain linkage, you
usually have to use file scope. (But see below.)

The main glitch in all this is that any identifier can be obscured by
another identically-spelled identifier that is declared in an
inner scope. For instance:

int file_scope_external_linkage;
static double file_scope_internal_linkage;

/* note: function identifiers always have file scope */
void func_external_linkage(void) {
char block_scope; /* no linkage */

block_scope = 'a';
{
float block_scope; /* also no linkage */
block_scope = 3.14159265;
}
}

Here there are two separate things, both named "block_scope", that
are still separate things. They both nave no linkage, and the
"outer" identifier named "block_scope" *would* be useable inside
the inner braces, except that it is "shadowed" by the inner name.
The char variable would be "visible" in the inner block; you just
cannot refer to it by name because the name is "captured" by an
"even-more-in-scope / more-visible" float variable.

The second glitch in this is the "extern" keyword. The meaning
of the "extern" keyword is, in a word, convoluted. In *most* cases
it means the obvious thing -- "external", as in "external linkage".
This gives you the ability to declare an identifier with external
linkage, yet block scope:

void somefunc(void) {
extern int somevar; /* block scope but external linkage */
...
}

In one case, though, "extern" actually means the same thing as the
"static" keyword. If (and only if) you use extern on a file scope
identifier that has already been declared as having internal linkage
(i.e., where the internal linkage is in scope), the "extern" keyword
gives that identifier internal linkage again (redundantly):

static int useless_var; /* file scope, internal linkage */
extern int useless_var; /* file scope, *internal* linkage (!) */

If you reverse the order, "bad things" happen:

extern int shared_var; /* file scope, external linkage */
static int shared_var; /* ERROR */

This attempts to give "shared_var" both internal and external
linkage. No diagnostic is required, and the behavior is undefined.

(The simplest rule here is "don't use both extern and static on
the same name". You only need to look up the exact rules about
how this all works when you are dealing with "bad" code. Even
then, the undefined aspect means that you may have to find out
what your particular implementation did, in order to figure out
what is going on with a given program.)

(I would argue that "avoid using the extern keyword inside block
scope" is also a good rule, although for temporary hacks, it can
be useful. The mixing of extern and static is *not* useful: the
well-defined version can be rewritten to just use the "static"
keyword each time, resulting in more-understandable code, at no
cost in code size or complexity.)
 
M

mdh

Right: linkage tells you where, within and between separate
translation units, the identifier will be "linked" to another
identifier that is spelled sufficiently similarly.


I think it is closer to say that scope tells you where the name
can be "seen".  There are only two "important" scopes: block and
file.  (There are two more, "function scope" and "function prototype
scope".  The former is strictly for goto-labels, and the latter is
a bit of a hack, being a substitute for block scope where there is
no brace-pair {...} to mark a block, but instead are just the
parentheses (...) that mark the function prototype.  Function
prototype scope is thus really just "block scope in drag".  Meanwhile,
"function scope" is really just "the outermost block of the containing
function" scope, and hence again is actually just a form of block
scope.)

An identifier that has file scope can be seen from whatever point
it is declared up to the end of the translation unit.  An identifier
with block scope can be seen up until the block is closed.  (As
noted above, a "function prototype" is closed by a closing parenthesis,
and the "function scope" for a goto label is closed by the closing
brace that ends the function body.  So these identifiers' scopes
end in exactly the same way as block-scope identifiers.)

There is a connection -- exactly how deep or strong can be debated
-- between the concepts, as an identifier with block scope (or the
pseudo-block-scope that you get with function and function-prototype
scopes) normally has "no linkage".  In order to obtain linkage, you
usually have to use file scope.  (But see below.)

The main glitch in all this is that any identifier can be obscured by
another identically-spelled identifier that is declared in an
inner scope.  For instance:

    int file_scope_external_linkage;
    static double file_scope_internal_linkage;

    /* note: function identifiers always have file scope */
    void func_external_linkage(void) {
        char block_scope; /* no linkage */

        block_scope = 'a';
        {
            float block_scope; /* also no linkage */
            block_scope = 3.14159265;
        }
    }

Here there are two separate things, both named "block_scope", that
are still separate things.  They both nave no linkage, and the
"outer" identifier named "block_scope" *would* be useable inside
the inner braces, except that it is "shadowed" by the inner name.
The char variable would be "visible" in the inner block; you just
cannot refer to it by name because the name is "captured" by an
"even-more-in-scope / more-visible" float variable.

The second glitch in this is the "extern" keyword.  The meaning
of the "extern" keyword is, in a word, convoluted.  In *most* cases
it means the obvious thing -- "external", as in "external linkage".
This gives you the ability to declare an identifier with external
linkage, yet block scope:

    void somefunc(void) {
        extern int somevar; /* block scope but external linkage */
        ...
    }

In one case, though, "extern" actually means the same thing as the
"static" keyword.  If (and only if) you use extern on a file scope
identifier that has already been declared as having internal linkage
(i.e., where the internal linkage is in scope), the "extern" keyword
gives that identifier internal linkage again (redundantly):

    static int useless_var; /* file scope, internal linkage */
    extern int useless_var; /* file scope, *internal* linkage (!) */

If you reverse the order, "bad things" happen:

    extern int shared_var; /* file scope, external linkage */
    static int shared_var; /* ERROR */

This attempts to give "shared_var" both internal and external
linkage.  No diagnostic is required, and the behavior is undefined.

(The simplest rule here is "don't use both extern and static on
the same name".  You only need to look up the exact rules about
how this all works when you are dealing with "bad" code.  Even
then, the undefined aspect means that you may have to find out
what your particular implementation did, in order to figure out
what is going on with a given program.)

(I would argue that "avoid using the extern keyword inside block
scope" is also a good rule, although for temporary hacks, it can
be useful.  The mixing of extern and static is *not* useful: the
well-defined version can be rewritten to just use the "static"
keyword each time, resulting in more-understandable code, at no
cost in code size or complexity.)

Chris...thank you very much for that very detailed and clear
explanation.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,565
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top