"static" objects and functions

J

Jess

Hello,

I learned that there are five kinds of static objects, namely

1. global objects
2. object defined in namespace scope
3. object declared static instead classes
4. objects declared static inside functions (i.e. local static
objects)
5. objects declared at file scope.

I have seen the examples of (3) and (4) above, can someone please give
me some examples and their purpose for the other types of static
objects?

Moreover, I've seen an extern statement:

class A{...};
extern A a;

which is said to be a definition for static object "a". Why is this a
static object without "static" keyword?

In addition to static objects, there are static functions. I think a
static member function, such as

class A{
static void f();
};
means it doesn't require any instance of A, and can operate on class
A. Is this right? Then I'm wondering if there's any static non-
member function, and if there is, when is it good to use it?

The example "extern A a" above also raises another question. Should I
regard it as a declaration that says there's an object "a" defined in
another source file, or, shall I regard it as a definition, since its
default constructor may be called?

Many thanks,
Jess
 
J

jeffjohnson_alpha

I learned that there are five kinds of static objects, namely

1. global objects
2. object defined in namespace scope
3. object declared static instead classes
4. objects declared static inside functions (i.e. local static
objects)
5. objects declared at file scope.

I have seen the examples of (3) and (4) above, can someone please give
me some examples and their purpose for the other types of static
objects?

somefile.hxx:
------------

struct A { } ;

extern A object_in_global_namespace ;

namespace foo {
extern A object_in_foo_namespace ;
}

struct X
{
static A object_inside_class ;
} ;

void function_with_local_static() ;

somefile.cxx:
------------

A object_in_global_namespace ;

namespace foo {
A object_in_foo_namespace ;
}

A X::eek:bject_inside_class ;

void function_with_local_static()
{
static A local_static ;
// ...
}

namespace {
A internal_linkage_object ; // ("file scope" object)
}
Moreover, I've seen an extern statement:

class A{...};
extern A a;

which is said to be a definition for static object "a". Why is this a
static object without "static" keyword?

"extern A a" is a *declaration* of a global object. It says, "when
you link, expect to find the definition somewhere." The defintion,
"A a", is placed inside a source file (not a header).

You are placing way too much emphasis on the literal meaning of the
word "static". It has some historical baggage which I will not dive
into. In modern C++, the only use of "static" should be inside class
definitions and inside functions. In the former case, it is used to
differentiate between per-instance and per-class; in the latter case,
it is used to differentiate between automatic storage and persistent
(static) storage.
In addition to static objects, there are static functions. I think a
static member function, such as

class A{
static void f();
};

means it doesn't require any instance of A, and can operate on class
A. Is this right? Then I'm wondering if there's any static non-
member function, and if there is, when is it good to use it?

If you put "static" in front of a regular function, that's deprecated
usage. It originally meant internal linkage, but that's done with
anonymous namespaces now. Don't do that. Again, don't read too much
into the literal meaning of the word.
The example "extern A a" above also raises another question. Should I
regard it as a declaration that says there's an object "a" defined in
another source file, or, shall I regard it as a definition, since its
default constructor may be called?

The former. "extern A a" is a declaration. It does not declare that
the object is constructed with the default constructor. Where it is
defined, it may be constructed with any constructor, e.g., "A a(44)".
 
J

jeffjohnson_alpha

You are placing way too much emphasis on the literal meaning of the
word "static". [...] In the former case, it is used to differentiate
between per-instance and per-class [...]

Argh, I had my mind in ruby mode when I wrote "per-class" (classes in
ruby are singleton objects which hold per-class data). Of course this
is not the case in C++; the storage of static class members is the
regular static storage.
 
M

Markus Moll

Hi

namespace {
A internal_linkage_object ; // ("file scope" object)
} [...]
If you put "static" in front of a regular function, that's deprecated
usage. It originally meant internal linkage, but that's done with
anonymous namespaces now. Don't do that. Again, don't read too much
into the literal meaning of the word.

That's incorrect. Names declared in unnamed namespaces still have external
linkage. However, there is no (portable) way to access the named object
from within another translation unit.

Markus
 
J

Jess

Hi



namespace {
A internal_linkage_object ; // ("file scope" object)
} [...]
If you put "static" in front of a regular function, that's deprecated
usage. It originally meant internal linkage, but that's done with
anonymous namespaces now. Don't do that. Again, don't read too much
into the literal meaning of the word.

That's incorrect. Names declared in unnamed namespaces still have external
linkage. However, there is no (portable) way to access the named object
from within another translation unit.

If it still has external linkage, then why is it not accessible from
another translation unit? I thought "external linkage" means it's
visible outside its own translation unit...

Thanks,
Jess
 
J

James Kanze

namespace {
A internal_linkage_object ; // ("file scope" object)
} [...]
If you put "static" in front of a regular function, that's deprecated
usage. It originally meant internal linkage, but that's done with
anonymous namespaces now. Don't do that. Again, don't read too much
into the literal meaning of the word.
That's incorrect. Names declared in unnamed namespaces still have external
linkage. However, there is no (portable) way to access the named object
from within another translation unit.
If it still has external linkage, then why is it not accessible from
another translation unit?

It is, in some very special cases. (It can be used in the
instantiation of an exported template, for example.) Generally,
however, there is no way to name it.
I thought "external linkage" means it's
visible outside its own translation unit...

It is visible, at least conceptually. But since you have no way
to refer to it, it's "visibility" is rather accademic. And of
course, visibility isn't really the word you want. External
linkage means that the same (fully qualified) name in different
translation units refers to the same, single object. When you
write:
namespace { int x ; }
this defines an object with type int and the name <secret>::x.
Any references to <secret>::x, from any translation unit in the
entire program, refer to the same object. The compiler,
however, generates a different <secret> for each translation
unit, and generates it in a way that you cannot even
accidentally hit on it. So about the only way you can refer to
it in another translation unit is when instantiating an exported
template.
 
J

James Kanze

For some reason, Google won't let me read your original posting,
so I'll answer here...

What do you mean by "static objects": objects declared with the
keyword static, or objects with static lifetime. The two are
only vaguely related, and you can also use the keyword static to
declare functions. For historical reasons, the keyword static
is overloaded, and depending on context, it affects both object
lifetime and linkage. Roughly speaking:

-- At namespace scope, the keyword static means that the symbol
being defined has internal linkage, rather than external
(which is the default at namespace scope). All objects
declared at namespace scope (with or without the keyword
static) have static lifetime. (Lifetime is irrelevant with
regards to functions.)

-- At class scope, static means that the object or function is
independant of any instance of the class. All symbols
declared at class scope have external linkage; objects
declared with static have static lifetime (as opposed to a
lifetime linked to that of the containing instance of the
class type).

-- At local scope, only objects (not functions) can be declared
static; such objects have static lifetime. (All objects
declared at local scope, unless explicitly declared extern,
have no linkage. Functions declared at local scope always
have external linkage.)

With regards to your exact question, I'm not too sure what
you're asking. A "global object" is normally an object declared
and defined in the global namespace without the static keyword,
i.e. an object in namespace scope and with external linkage. By
definition, it can't be declared static (but it always has
static lifetime), because if it were, it wouldn't be a global
object. And there is no "file scope" in C++; if by "file scope"
you mean outside of any namespace, class or function, then that
is "global scope", or the "global namespace".

Note too that the use of static at namespace scope is
deprecated. It is generally preferred to use an anonymous
namespace. (On the other hand, the names of variables declared
"const" have internal linkage, just as if they were declared
static, unless they are explicitly declared "extern".)

As to when you would use them: the classical singleton idiom is
a good example of static used at class scope:

class Singleton
{
public:
static Singleton& instance() ;
// ...
private:
static Singleton* ourInstance ;
} ;

The function instance() can (and will be) called without an
instance of the object, and the variable ourInstance will have
static lifetime, existing before the first instance is created,
and after the last one is destructed.

At local scope, one might use a static variable to keep track of
recursion:

void*
operator new( size_t n )
{
static bool recursing = false ;
void* result = NULL ;
if ( recursing ) {
result = getMemory( n ) ;
} else {
recursing = true ;
std::cerr << "allocating " << n << " bytes at " ;
result = getMemory( n ) ;
std::cerr << result << std::endl ;
recursing = false ;
}
return result ;
}

This is necessary here, since outputting to std::cerr could very
easily end up calling operator new.
 
J

Jess

For some reason, Google won't let me read your original posting,
so I'll answer here...

What do you mean by "static objects": objects declared with the
keyword static, or objects with static lifetime. The two are
only vaguely related, and you can also use the keyword static to
declare functions. For historical reasons, the keyword static
is overloaded, and depending on context, it affects both object
lifetime and linkage. Roughly speaking:

-- At namespace scope, the keyword static means that the symbol
being defined has internal linkage, rather than external
(which is the default at namespace scope). All objects
declared at namespace scope (with or without the keyword
static) have static lifetime. (Lifetime is irrelevant with
regards to functions.)

Many thanks for your answers. :) There're still a few issues that
bother me. Although, as you've said, static under namespace is
deprecated, I feel not so comfortable if I don't completely understand
it. :) If I have

namespace N{
A a;
}

then "a" has external linkage, but if I have

namespace N{
static A a;
}

then "a" has internal linkage, is this right? I think "internal
linkage" means it's only accessible within this current translation
unit, is this also right? Furthermore, I tried one example as
follows:

//test.h
class A{
public:
int x;
A():x(10){}
};

namespace foo{
static extern A b;
}

//test.cpp
#include "test.h"

namespace foo{
A b;
};

//testT.cpp
#include<iostream>
#include "test.h"

using namespace std;

int main(){
cout << foo::b.x << endl;
return 0;
}

However, the compiler error was

"multiple storage classes in declaration of 'b'"

What does this mean?

-- At class scope, static means that the object or function is
independant of any instance of the class. All symbols
declared at class scope have external linkage; objects
declared with static have static lifetime (as opposed to a
lifetime linked to that of the containing instance of the
class type).

-- At local scope, only objects (not functions) can be declared
static; such objects have static lifetime. (All objects
declared at local scope, unless explicitly declared extern,
have no linkage. Functions declared at local scope always
have external linkage.)

The only local scope that I've seen is within a function body, is
there any other kind of local scope? How can a function be declared
within such local scope? By the way, I think "no linkage" means it is
only accessible within that local scope where it's defined, is this
correct?
With regards to your exact question, I'm not too sure what
you're asking. A "global object" is normally an object declared
and defined in the global namespace without the static keyword,
i.e. an object in namespace scope and with external linkage. By
definition, it can't be declared static (but it always has
static lifetime), because if it were, it wouldn't be a global
object. And there is no "file scope" in C++; if by "file scope"
you mean outside of any namespace, class or function, then that
is "global scope", or the "global namespace".

My interpretation about "global" namespace is that I don't use any
"namespace" to surround my object/function, please correct me if I'm
wrong. Then, why did you say a global object is "an object in
namespace scope and with external linkage"? In other words, do I still
need to use "namespace" to wrap it up?

I got the terms "global objects" and "objects at file scope" from the
book Effective C++. My understanding about them is that a global
object has external linkage (accessible from other translation units),
and a file-scope-object is only accessible within that translation
unit (but not limited to any local scope within that translation
unit). Is this not the intended meaning of the author?
Note too that the use of static at namespace scope is
deprecated. It is generally preferred to use an anonymous
namespace. (On the other hand, the names of variables declared
"const" have internal linkage, just as if they were declared
static, unless they are explicitly declared "extern".)

I tried another example, which also failed to compile.

//test.h
namespace foo{
static extern const int x;
};

//test.cpp
#include "test.h"

namespace foo{
static const int x = 10;
}

#include "test.h"
#include<iostream>

using namespace std;
int main(){
cout << foo::x << endl;
return 0;
}

However, after I removed the static keyword, it compiled and worked.
Does a const inside a namespace have external or internal linkage?
Moreover, it just seems to me that I can never declare "static" within
a namespace.

Moreover, do all objects that have external linkage have static
lifetime? not a single exception?

Finally, I noticed that sometimes when I declare a static object, I
need "static" keyword, but when I define it, I don't need "static".
Does this depend on the context or, do we not need "static" in general
when we define it?

Thanks very much indeed,
Jess
 
J

Jess

For some reason, Google won't let me read your original posting,
so I'll answer here...

What do you mean by "static objects": objects declared with the
keyword static, or objects with static lifetime. The two are
only vaguely related, and you can also use the keyword static to
declare functions. For historical reasons, the keyword static
is overloaded, and depending on context, it affects both object
lifetime and linkage. Roughly speaking:

-- At namespace scope, the keyword static means that the symbol
being defined has internal linkage, rather than external
(which is the default at namespace scope). All objects
declared at namespace scope (with or without the keyword
static) have static lifetime. (Lifetime is irrelevant with
regards to functions.)

Many thanks for your answers. :) There're still a few issues that
bother me. Although, as you've said, static under namespace is
deprecated, I feel not so comfortable if I don't completely understand
it. :) If I have

namespace N{
A a;
}

then "a" has external linkage, but if I have

namespace N{
static A a;
}

then "a" has internal linkage, is this right? I think "internal
linkage" means it's only accessible within this current translation
unit, is this also right? Furthermore, I tried one example as
follows:

//test.h
class A{
public:
int x;
A():x(10){}
};

namespace foo{
static extern A b;
}

//test.cpp
#include "test.h"

namespace foo{
A b;
};

//testT.cpp
#include<iostream>
#include "test.h"

using namespace std;

int main(){
cout << foo::b.x << endl;
return 0;
}

However, the compiler error was

"multiple storage classes in declaration of 'b'"

What does this mean?

-- At class scope, static means that the object or function is
independant of any instance of the class. All symbols
declared at class scope have external linkage; objects
declared with static have static lifetime (as opposed to a
lifetime linked to that of the containing instance of the
class type).

-- At local scope, only objects (not functions) can be declared
static; such objects have static lifetime. (All objects
declared at local scope, unless explicitly declared extern,
have no linkage. Functions declared at local scope always
have external linkage.)

The only local scope that I've seen is within a function body, is
there any other kind of local scope? How can a function be declared
within such local scope? By the way, I think "no linkage" means it is
only accessible within that local scope where it's defined, is this
correct?
With regards to your exact question, I'm not too sure what
you're asking. A "global object" is normally an object declared
and defined in the global namespace without the static keyword,
i.e. an object in namespace scope and with external linkage. By
definition, it can't be declared static (but it always has
static lifetime), because if it were, it wouldn't be a global
object. And there is no "file scope" in C++; if by "file scope"
you mean outside of any namespace, class or function, then that
is "global scope", or the "global namespace".

My interpretation about "global" namespace is that I don't use any
"namespace" to surround my object/function, please correct me if I'm
wrong. Then, why did you say a global object is "an object in
namespace scope and with external linkage"? In other words, do I still
need to use "namespace" to wrap it up?

I got the terms "global objects" and "objects at file scope" from the
book Effective C++. My understanding about them is that a global
object has external linkage (accessible from other translation units),
and a file-scope-object is only accessible within that translation
unit (but not limited to any local scope within that translation
unit). Is this not the intended meaning of the author?
Note too that the use of static at namespace scope is
deprecated. It is generally preferred to use an anonymous
namespace. (On the other hand, the names of variables declared
"const" have internal linkage, just as if they were declared
static, unless they are explicitly declared "extern".)

I tried another example, which also failed to compile.

//test.h
namespace foo{
static extern const int x;
};

//test.cpp
#include "test.h"

namespace foo{
static const int x = 10;
}

#include "test.h"
#include<iostream>

using namespace std;
int main(){
cout << foo::x << endl;
return 0;
}

However, after I removed the static keyword, it compiled and worked.
Does a const inside a namespace have external or internal linkage?
Moreover, it just seems to me that I can never declare "static" within
a namespace.

Moreover, do all objects that have external linkage have static
lifetime? not a single exception?

Finally, I noticed that sometimes when I declare a static object, I
need "static" keyword, but when I define it, I don't need "static".
Does this depend on the context or, do we not need "static" in general
when we define it?

Thanks very much indeed,
Jess
 
J

James Kanze

Many thanks for your answers. :) There're still a few issues that
bother me. Although, as you've said, static under namespace is
deprecated, I feel not so comfortable if I don't completely understand
it. :) If I have
namespace N{
A a;
}
then "a" has external linkage, but if I have
namespace N{
static A a;
}
then "a" has internal linkage, is this right?
Correct.

I think "internal linkage" means it's only accessible within
this current translation unit, is this also right?

Not really. Although it's common to think of it in such terms,
linkage is really concerned with whether two (fully qualified)
names refer to the same object (or function, or class, or
whatever). In the above, the fully qualified name is N::a, and
the name is "accessible" in any translation unit which declares
it. In the first case, it has external linkage, which means
that all of the names N::a refer to the same, unique object,
regardless of which translation unit they are in. In the
second, with the static, the name as internal linkage: all of
the declarations within a single translation unit refer to the
same, unique object, but each translation unit has a different
object.
Furthermore, I tried one example as follows:
//test.h
class A{
public:
int x;
A():x(10){}

};
namespace foo{
static extern A b;

Did this compile? It shouldn't: both static and extern are
"storage class specifiers", and "At most one
storage-class-specifier shall appear in a given
decl-specifier-seq."
//test.cpp
#include "test.h"
namespace foo{
A b;
};
//testT.cpp
#include<iostream>
#include "test.h"
using namespace std;
int main(){
cout << foo::b.x << endl;
return 0;
}
However, the compiler error was
"multiple storage classes in declaration of 'b'"
What does this mean?

Exactly what it says. The keywords "auto", "register",
"static", "extern" and "mutable" are storage class specifiers,
and the standard says that at most one can appear in any given
declaration.

Formally, this is a purely syntactic restriction, but the
motivation is that in general, the semantics of each of these
keywords conflict. (One could argue about auto and register, I
suppose.) In this particular case, "static" says that the
variable has internal linkage, and "extern" says that it has
external linkage. Extern also says that it is only a
declaration, and not a definition. The C++ declaration syntax
just grew, and isn't always as coherent or as logical as one
might like. Thus:

namespace A {
int a1 ; // external linkage, definition.
extern int a2 ; // external linkage, declaration.
static int a3 ; // internal linkage, definition.
int const a4 ; // *internal linkage, definition.
extern int const a5 ; // external linkage, declaration.
static int const a6 ; // *internal linkage, definition.
int i1 = 42 ; // external linkage, definition.
extern int i2 = 42 ; // external linkage, definition!
static int i3 = 42 ; // internal linkage, definition.
int const i4 = 42 ; // internal linkage, definition.
extern int const i5 = 42 ; // external linkage, definition.
static int const i6 = 42 ; // internal linkage, definition.
}

The declarations marked * are in fact illegal, as a definition
of a const object is illegal unless the object either has a
non-trivial constructor or an initializer. Note that the table
is full of incoherences and oddities---note in particular the
role of const (which logically is completely orthogonal), and
the fact that an initialization forces the declaration to be a
definition, even if it is extern. (And that to define a const
object with external linkage, you have to use extern.)

Also, these declarations suppose that the object has not been
previously declared. Something like:

namespace A {
static int const x = 42 ;
extern int const x ;
}

is perfectly legal---linkage is established by the first
declaration, and cannot be changed later, and extern only means
external linkage if there has been no previous declaration. On
the other hand, inversing them is not---static means internal
linkage, always, so the linkages conflict.
The only local scope that I've seen is within a function body, is
there any other kind of local scope?

Local scope is always within a function body, or more exactly, a
compound statement (but a compound statement can only
occur within a function body).
How can a function be declared within such local scope?

void
f()
{
std::vector< int > v( std::istream_iterator< int >( file ),
std::istream_iterator< int >() ) ;
}

:). The problem is more often, how can we ensure that a
definition is not a function declaration in local scope; in the
above, the programmer probably wanted to define a local variable
v, using the two iterator constructor of vector. In fact, he has
declared a function (with external linkage, in global scope)
taking two arguments, and istream_iterator<int>, and a pointer
to a function returning and istream_iterator<int>, and returning
a vector<int>.

On the other hand, the intent of:

void
f()
{
extern double g( double ) ;
// ...
}

seems quite clear, although it's not the sort of thing one would
encourage.
By the way, I think "no linkage" means it is only accessible
within that local scope where it's defined, is this correct?

No linkage means that no other declaration can refer to the
object in question. For example:

void
f()
{
int a ; // No linkage...
{
int a ; // So this can't be the same variable.
// ...
}
}

There's an interesting (perverse?) example of this in the
standard:

static int i ; // 1.
void g()
{
int i ; // 2. Hides the static 1.
{
extern int i ; // 3.
}
}

The line labeled 3 refers to yet a third object (not defined
here): since the declaration at 2 hides the declaration at 1,
the compiler doesn't "see" it, and since the declaration at 2
has no linkage, the declaration at 3 declares a new object, with
external linkage (different from the object with internal
linkage defined at 1).

(And if you aren't thoroughly confused yet, you should be.)
My interpretation about "global" namespace is that I don't use any
"namespace" to surround my object/function, please correct me if I'm
wrong.

Correct. The concept is that the entire translation unit is
encapsulated in an outer namespace, which is called the global
namespace.
Then, why did you say a global object is "an object in
namespace scope and with external linkage"? In other words, do I still
need to use "namespace" to wrap it up?

No. Namespace scope includes objects defined in this imaginary
namespace which encapsulates the entire translation unit. (On
the other hand, it doesn't include built in types, like int.
Which occasionally causes problems when code is counting on
ADL.)
I got the terms "global objects" and "objects at file scope" from the
book Effective C++.

They're frequently used terms. File scope is the term in the C
standard, and was the term in pre-namespace specifications of
C++. Global objects is a pretty good, succinct term for
something which we all understand, even if it has no formal
backing in the standard. (Note too that the original version of
Effective C++ pre-dates namespaces, and that it's entirely
possible that Scott didn't fully update his terminology in later
versions.)
My understanding about them is that a global
object has external linkage (accessible from other translation units),
and a file-scope-object is only accessible within that translation
unit (but not limited to any local scope within that translation
unit). Is this not the intended meaning of the author?

Not at all. First, of course, scope is more or less orthogonal
to linkage: you can declare objects with external linkage in
block scope, and only have the name visible (in that translation
unit) in block scope. Other than that, file-scope is just the
traditional name for global namespace scope, or global scope.
When used in the context of C++, all three mean exactly the same
thing. (Scope and linkage aren't 100% orthogonal, since an
object declared at namespace scope will always have linkage.)
I tried another example, which also failed to compile.

//test.h
namespace foo{
static extern const int x;

Again, two storage class specifiers aren't allowed.
//test.cpp
#include "test.h"
namespace foo{
static const int x = 10;
}
#include "test.h"
#include<iostream>
using namespace std;
int main(){
cout << foo::x << endl;
return 0;
}
However, after I removed the static keyword, it compiled and
worked.

Because the first declaration established the linkage (as
external). See above. And don't expect consistency:).
Does a const inside a namespace have external or internal linkage?

Yes:).

A const at namespace scope has internal linkage by default. It
will have external linkage if either 1) it is declared with the
storage class specifier extern, or 2) there is a previous
declaration of the same object which has external linkage.
Moreover, it just seems to me that I can never declare "static" within
a namespace.

Sure you can:

namespace A {
static int x = 32 ;
}

Do this in several different translation units, and you'll find
that the modifications to x in one are not visible in the other.
Because the x in each translation unit is a different object.
Moreover, do all objects that have external linkage have static
lifetime? not a single exception?

Class members have external linkage, and don't (necessarily) have
static lifetime. What is true is that all objects at namespace
scope have static lifetime, and that all objects declared static
(regardless of their linkage or scope) have static lifetime.
Finally, I noticed that sometimes when I declare a static object, I
need "static" keyword, but when I define it, I don't need "static".
Does this depend on the context or, do we not need "static" in general
when we define it?

No. If their is a previous declaration visible (which has
linkage), the linkage is that of the previous declaration.
(Most of the time, the only declaration of a static variable is
also its definition.)
 
J

Jess

Not really. Although it's common to think of it in such terms,
linkage is really concerned with whether two (fully qualified)
names refer to the same object (or function, or class, or
whatever). In the above, the fully qualified name is N::a, and
the name is "accessible" in any translation unit which declares
it. In the first case, it has external linkage, which means
that all of the names N::a refer to the same, unique object,
regardless of which translation unit they are in. In the
second, with the static, the name as internal linkage: all of
the declarations within a single translation unit refer to the
same, unique object, but each translation unit has a different
object.



Did this compile? It shouldn't: both static and extern are
"storage class specifiers", and "At most one
storage-class-specifier shall appear in a given
decl-specifier-seq."


Exactly what it says. The keywords "auto", "register",
"static", "extern" and "mutable" are storage class specifiers,
and the standard says that at most one can appear in any given
declaration.

Formally, this is a purely syntactic restriction, but the
motivation is that in general, the semantics of each of these
keywords conflict. (One could argue about auto and register, I
suppose.) In this particular case, "static" says that the
variable has internal linkage, and "extern" says that it has
external linkage. Extern also says that it is only a
declaration, and not a definition. The C++ declaration syntax
just grew, and isn't always as coherent or as logical as one
might like. Thus:

namespace A {
int a1 ; // external linkage, definition.
extern int a2 ; // external linkage, declaration.
static int a3 ; // internal linkage, definition.
int const a4 ; // *internal linkage, definition.
extern int const a5 ; // external linkage, declaration.
static int const a6 ; // *internal linkage, definition.
int i1 = 42 ; // external linkage, definition.
extern int i2 = 42 ; // external linkage, definition!
static int i3 = 42 ; // internal linkage, definition.
int const i4 = 42 ; // internal linkage, definition.
extern int const i5 = 42 ; // external linkage, definition.
static int const i6 = 42 ; // internal linkage, definition.
}

The declarations marked * are in fact illegal, as a definition
of a const object is illegal unless the object either has a
non-trivial constructor or an initializer. Note that the table
is full of incoherences and oddities---note in particular the
role of const (which logically is completely orthogonal), and
the fact that an initialization forces the declaration to be a
definition, even if it is extern. (And that to define a const
object with external linkage, you have to use extern.)

Thank you so much for giving me these examples. :) There are really
so many incoherences, headache...Moreover, about the requirement on
"const" ("const object is illegal unless the object either has a non-
trivial constructor or an initializer"), is it universal or is it only
applicable when it's within a namespace?
Also, these declarations suppose that the object has not been
previously declared. Something like:

namespace A {
static int const x = 42 ;
extern int const x ;
}

is perfectly legal---linkage is established by the first
declaration, and cannot be changed later, and extern only means
external linkage if there has been no previous declaration. On
the other hand, inversing them is not---static means internal
linkage, always, so the linkages conflict.


Local scope is always within a function body, or more exactly, a
compound statement (but a compound statement can only
occur within a function body).


void
f()
{
std::vector< int > v( std::istream_iterator< int >( file ),
std::istream_iterator< int >() ) ;
}
:). The problem is more often, how can we ensure that a
definition is not a function declaration in local scope; in the
above, the programmer probably wanted to define a local variable
v, using the two iterator constructor of vector. In fact, he has
declared a function (with external linkage, in global scope)
taking two arguments, and istream_iterator<int>, and a pointer
to a function returning and istream_iterator<int>, and returning
a vector<int>.

Why is above a declaration? It doesn't look like a definition either.
To me, it looks like calling the function "v": the first argument
passed to "v" is an iterator (constructed from "file") and the second
argument is also an iterator, constructed by the default
constructor.
On the other hand, the intent of:

void
f()
{
extern double g( double ) ;
// ...
}

seems quite clear, although it's not the sort of thing one would
encourage.


No linkage means that no other declaration can refer to the
object in question. For example:

void
f()
{
int a ; // No linkage...
{
int a ; // So this can't be the same variable.
// ...
}
}

There's an interesting (perverse?) example of this in the
standard:

static int i ; // 1.
void g()
{
int i ; // 2. Hides the static 1.
{
extern int i ; // 3.
}
}

The line labeled 3 refers to yet a third object (not defined
here): since the declaration at 2 hides the declaration at 1,
the compiler doesn't "see" it, and since the declaration at 2
has no linkage, the declaration at 3 declares a new object, with
external linkage (different from the object with internal
linkage defined at 1).

I can see that declaration at line 2 hides declaration at 1. I think
"i" at line 2 is also a definition, which is visable to inner block
(i.e. line 3). Therefore, I think line 3 is saying declare the "i" at
line 2 as external. I thought in general, objects declared at outer
block are always visible in the inner blocks, unless there's a re-
declaration/definition of it in the inner blocks, is this wrong?

(And if you aren't thoroughly confused yet, you should be.)

I am thoroughly confused, as you've correctly guessed... :(

Thanks,
Jess
 
J

James Kanze

[...]
Thank you so much for giving me these examples. :) There are really
so many incoherences, headache...Moreover, about the requirement on
"const" ("const object is illegal unless the object either has a non-
trivial constructor or an initializer"), is it universal or is it only
applicable when it's within a namespace?

It's universal, but it applies (obviously, if you think about
it) when the object is created, not when it is declared. So:

struct Toto
{
int const titi ; // No initializer here...
Toto() ;
} ;

Toto::Toto()
: titi( 42 ) // initializer required here...
{
}

There is a special case for const static members of integral
type; the initializer can appear in the declaration (in the
class definition) rather than in the definition of the object.

[...]
Why is above a declaration?

Because the standard says that if something can be interpreted
as a declaration, it is. Both of the sub-expressions
"std::istream_iterator< int >( file )" and
"std::istream_iterator< int >()" can be interpreted as
declarations. And if they are declarations, then the result is
the declaration of a function. To make it clearer, replace the
complicated type names with simple symbols: A for
"std::vector< int >", and B for "std::istream_iterator< int >":

A v( B (file), B() ) ;

Now, remove the superfluous parentheses, and rewrite the second
declaration according to the special rules which apply to
function parameters, and you get:

A v( B file, B (*)() ) ;

Which looks very much like a function declaration, a function v
taking two arguments, a B, and a pointer to a function returning
a B, and returning an A.
It doesn't look like a definition either.
To me, it looks like calling the function "v": the first argument
passed to "v" is an iterator (constructed from "file") and the second
argument is also an iterator, constructed by the default
constructor.

And what does the "std::vector< int >" do in the statement? If
a statement starts with the name of a type, and that name is not
immediately followed by a '(', it's either a declaration of some
sort, or completely illegal. (If the name of the type is
immediately followed by a '(', it might still be a declaration.
Or it might not be, depending on what follows.)

[...]
I can see that declaration at line 2 hides declaration at 1. I think
"i" at line 2 is also a definition, which is visable to inner block
(i.e. line 3).

That's correct so far.
Therefore, I think line 3 is saying declare the "i" at
line 2 as external.

That would be logical, and it would be logical (IMHO) for the
above to be an error, since there are conflicting linkage
specifications. According to the standard, however, the "i" in
line 2 has no binding, so no other declaration can refer to it.
Thus, since line 3 can't refer to it, and line 1. isn't visible
at this point, line 3 declares still another i.

Whether you or I think that this is a good idea, or the way it
should be, is irrelevant. The above example is taken directly
from the standard.
I thought in general, objects declared at outer
block are always visible in the inner blocks, unless there's a re-
declaration/definition of it in the inner blocks, is this wrong?
I am thoroughly confused, as you've correctly guessed... :(

Well, you seemed to want to know all of the details. And they
are confusing. I've written compilers in the past, and worked
with language standards for something like 20 years, and I still
have to go very, very slowly when attacking this in C++. (And
if you think that this is confusing, wait until you attack
function overload resolution, or name binding in templates.)
 
J

Jess

[...]
Thank you so much for giving me these examples. :) There are really
so many incoherences, headache...Moreover, about the requirement on
"const" ("const object is illegal unless the object either has a non-
trivial constructor or an initializer"), is it universal or is it only
applicable when it's within a namespace?

It's universal, but it applies (obviously, if you think about
it) when the object is created, not when it is declared. So:

struct Toto
{
int const titi ; // No initializer here...
Toto() ;
} ;

Toto::Toto()
: titi( 42 ) // initializer required here...
{
}

There is a special case for const static members of integral
type; the initializer can appear in the declaration (in the
class definition) rather than in the definition of the object.

[...]


Why is above a declaration?

Because the standard says that if something can be interpreted
as a declaration, it is. Both of the sub-expressions
"std::istream_iterator< int >( file )" and
"std::istream_iterator< int >()" can be interpreted as
declarations. And if they are declarations, then the result is
the declaration of a function. To make it clearer, replace the
complicated type names with simple symbols: A for
"std::vector< int >", and B for "std::istream_iterator< int >":

A v( B (file), B() ) ;

Now, remove the superfluous parentheses, and rewrite the second
declaration according to the special rules which apply to
function parameters, and you get:

A v( B file, B (*)() ) ;

Which looks very much like a function declaration, a function v
taking two arguments, a B, and a pointer to a function returning
a B, and returning an A.
It doesn't look like a definition either.
To me, it looks like calling the function "v": the first argument
passed to "v" is an iterator (constructed from "file") and the second
argument is also an iterator, constructed by the default
constructor.

And what does the "std::vector< int >" do in the statement? If
a statement starts with the name of a type, and that name is not
immediately followed by a '(', it's either a declaration of some
sort, or completely illegal. (If the name of the type is
immediately followed by a '(', it might still be a declaration.
Or it might not be, depending on what follows.)

[...]


I can see that declaration at line 2 hides declaration at 1. I think
"i" at line 2 is also a definition, which is visable to inner block
(i.e. line 3).

That's correct so far.
Therefore, I think line 3 is saying declare the "i" at
line 2 as external.

That would be logical, and it would be logical (IMHO) for the
above to be an error, since there are conflicting linkage
specifications. According to the standard, however, the "i" in
line 2 has no binding, so no other declaration can refer to it.
Thus, since line 3 can't refer to it, and line 1. isn't visible
at this point, line 3 declares still another i.

Thanks again. My email yesterday seemed to be deleted by google...
I'm still wondering why "i" at line2 is visible at line3, but there's
no binding for the "i" at line 2. No binding means no linkage, is
this correct? If so, is it completely useless to declare "i" at line
2? If I have another line after line 2, but before the "{" above line
3

cout << i << endl;

then I think "i" at line 2 gets printed. Does it mean the "{" above
line 3 makes "i" at line 2 have no binding?

Whether you or I think that this is a good idea, or the way it
should be, is irrelevant. The above example is taken directly
from the standard.


Well, you seemed to want to know all of the details. And they
are confusing. I've written compilers in the past, and worked
with language standards for something like 20 years, and I still
have to go very, very slowly when attacking this in C++. (And
if you think that this is confusing, wait until you attack
function overload resolution, or name binding in templates.)

I indeed like to have a completely clear picture, though I see it's
impossible for me at the moment. I just hope to be more confident
when I write programs if I know which variables are visible at which
place and whether I'm referring to a variable that I intend to.

Thanks a lot!
Jess
 
J

James Kanze

[...]
There's an interesting (perverse?) example of this in the
standard:
static int i ; // 1.
void g()
{
int i ; // 2. Hides the static 1.
{
extern int i ; // 3.
}
}
The line labeled 3 refers to yet a third object (not defined
here): since the declaration at 2 hides the declaration at 1,
the compiler doesn't "see" it, and since the declaration at 2
has no linkage, the declaration at 3 declares a new object, with
external linkage (different from the object with internal
linkage defined at 1).
I can see that declaration at line 2 hides declaration at 1. I think
"i" at line 2 is also a definition, which is visable to inner block
(i.e. line 3).
That's correct so far.
Therefore, I think line 3 is saying declare the "i" at
line 2 as external.
That would be logical, and it would be logical (IMHO) for the
above to be an error, since there are conflicting linkage
specifications. According to the standard, however, the "i" in
line 2 has no binding, so no other declaration can refer to it.
Thus, since line 3 can't refer to it, and line 1. isn't visible
at this point, line 3 declares still another i.
Thanks again. My email yesterday seemed to be deleted by google...

It's not an email, but a posting, and I also have the impression
that Google looses a few.
I'm still wondering why "i" at line2 is visible at line3, but there's
no binding for the "i" at line 2.

The "i" is visible because those are the rules of visibility in
C++ (and in most other scoped languages, I think). And the "i"
doesn't have linkage because that is also a rule of the
language.

Both of the rules, taken in isolation, make very good sense.
The problem is the interaction---since the "i" in 2 is visible,
I would normally expect that the declaration in 3 refers to it,
that it attempts to change the linkage, which isn't possible,
and so should be an error. But the standard says otherwise.

IMHO, it's not a real problem. There's never any reason to
declare an extern at local scope anyway---externs should always
be declared in header files, at namespace scope.
No binding means no linkage, is this correct?

No linkage is what I meant. No binding is a bit of sloppiness
on my part. (Binding is different than linkage, and isn't
relevant here.)
If so, is it completely useless to declare "i" at line 2? If
I have another line after line 2, but before the "{" above
line 3

static int i = 1 ; // 1.
void g()
{
std::cout << i ; // Outputs 1
int i = 2 ; // 2. Hides the static 1.
std::cout << i ; // Outputs 2
{
std::cout << i ; // Outputs 2
extern int i ; // 3. (Initialized to 3 elsewhere.
std::cout << i ; // Outputs 3
}
std::cout << i ; // Outputs 2
}

Although never for an extern, on very rare occasions, I've
introduced extra {} just to limit scope. In C++, this usually
occurs in order to ensure that the destructor is called at the
correct time, e.g.:

void
f()
{
// do something non critical...
{
scoped_lock l( someMutex ) ;
// locked region...
}
// unlocked here...
}
cout << i << endl;
then I think "i" at line 2 gets printed. Does it mean the "{" above
line 3 makes "i" at line 2 have no binding?

No. A variable declared at block scope (in a {...} in a
function) has no linkage by default; declaring it extern gives
it external linkage, unless there is a previous declaration
which has linkage and is visible.

The rules here are rather arbitrary, and I suspect that it's
another case of the committee just deciding that they had to
specify something, but it didn't matter much what. In good
code, you will not have any "extern" at block scope, so it
doesn't matter. But if you're writing a compiler, you have to
know what to do about it; a compiler has to work in a defined
manner even if fed "bad" code.
I indeed like to have a completely clear picture, though I see it's
impossible for me at the moment. I just hope to be more confident
when I write programs if I know which variables are visible at which
place and whether I'm referring to a variable that I intend to.

I understand totally, but be aware that even with over 15 years
experience in C++, there are aspects which remain hazy to me.
That doesn't necessarily stop me from writing correct code. In
this case, for example, the complication only involves cases
where you declare a variable extern at block scope. Don't do
that, and there's no problem. Avoid the same names for
different objects, and you don't have to worry about whether the
name refers to a file local static, or to a global. (I'm not
saying that the rules are intuitive, but they're generally clear
enough that one can learn them.)
 
J

Jess

[...]
There's an interesting (perverse?) example of this in the
standard:
static int i ; // 1.
void g()
{
int i ; // 2. Hides the static 1.
{
extern int i ; // 3.
}
}
The line labeled 3 refers to yet a third object (not defined
here): since the declaration at 2 hides the declaration at 1,
the compiler doesn't "see" it, and since the declaration at 2
has no linkage, the declaration at 3 declares a new object, with
external linkage (different from the object with internal
linkage defined at 1).
I can see that declaration at line 2 hides declaration at 1. I think
"i" at line 2 is also a definition, which is visable to inner block
(i.e. line 3).
That's correct so far.
Therefore, I think line 3 is saying declare the "i" at
line 2 as external.
That would be logical, and it would be logical (IMHO) for the
above to be an error, since there are conflicting linkage
specifications. According to the standard, however, the "i" in
line 2 has no binding, so no other declaration can refer to it.
Thus, since line 3 can't refer to it, and line 1. isn't visible
at this point, line 3 declares still another i.
Thanks again. My email yesterday seemed to be deleted by google...

It's not an email, but a posting, and I also have the impression
that Google looses a few.
I'm still wondering why "i" at line2 is visible at line3, but there's
no binding for the "i" at line 2.

The "i" is visible because those are the rules of visibility in
C++ (and in most other scoped languages, I think). And the "i"
doesn't have linkage because that is also a rule of the
language.

Both of the rules, taken in isolation, make very good sense.
The problem is the interaction---since the "i" in 2 is visible,
I would normally expect that the declaration in 3 refers to it,
that it attempts to change the linkage, which isn't possible,
and so should be an error. But the standard says otherwise.

IMHO, it's not a real problem. There's never any reason to
declare an extern at local scope anyway---externs should always
be declared in header files, at namespace scope.
No binding means no linkage, is this correct?

No linkage is what I meant. No binding is a bit of sloppiness
on my part. (Binding is different than linkage, and isn't
relevant here.)
If so, is it completely useless to declare "i" at line 2? If
I have another line after line 2, but before the "{" above
line 3

static int i = 1 ; // 1.
void g()
{
std::cout << i ; // Outputs 1
int i = 2 ; // 2. Hides the static 1.
std::cout << i ; // Outputs 2
{
std::cout << i ; // Outputs 2
extern int i ; // 3. (Initialized to 3 elsewhere.
std::cout << i ; // Outputs 3
}
std::cout << i ; // Outputs 2
}

Although never for an extern, on very rare occasions, I've
introduced extra {} just to limit scope. In C++, this usually
occurs in order to ensure that the destructor is called at the
correct time, e.g.:

void
f()
{
// do something non critical...
{
scoped_lock l( someMutex ) ;
// locked region...
}
// unlocked here...
}
cout << i << endl;
then I think "i" at line 2 gets printed. Does it mean the "{" above
line 3 makes "i" at line 2 have no binding?

No. A variable declared at block scope (in a {...} in a
function) has no linkage by default; declaring it extern gives
it external linkage, unless there is a previous declaration
which has linkage and is visible.

The rules here are rather arbitrary, and I suspect that it's
another case of the committee just deciding that they had to
specify something, but it didn't matter much what. In good
code, you will not have any "extern" at block scope, so it
doesn't matter. But if you're writing a compiler, you have to
know what to do about it; a compiler has to work in a defined
manner even if fed "bad" code.


I indeed like to have a completely clear picture, though I see it's
impossible for me at the moment. I just hope to be more confident
when I write programs if I know which variables are visible at which
place and whether I'm referring to a variable that I intend to.

I understand totally, but be aware that even with over 15 years
experience in C++, there are aspects which remain hazy to me.
That doesn't necessarily stop me from writing correct code. In
this case, for example, the complication only involves cases
where you declare a variable extern at block scope. Don't do
that, and there's no problem. Avoid the same names for
different objects, and you don't have to worry about whether the
name refers to a file local static, or to a global. (I'm not
saying that the rules are intuitive, but they're generally clear
enough that one can learn them.)

--
James Kanze (GABI Software) email:[email protected]
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Thanks a lot for clarifying the matter, I think I understand it, at
least for now. :)
Jess
 

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,994
Messages
2,570,223
Members
46,813
Latest member
lawrwtwinkle111

Latest Threads

Top