extern + functions

Jun 9, 2010 at 6:09pm
Why does this code compile?
1
2
3
4
5
6
7
8
9
10
11
12
extern void msg() // !
{ 
std::cout <<"msg";
}


int main()
{
msg();

}

I thought that extern specifies that function is implemented in other .cpp file or library/object file. But why my code compiles? And is there a difference between previous example and this:

1
2
3
4
5
6
7
// main.cpp
extern void msg():
int main()
{
msg();

}

1
2
3
// other_file.cpp
void msg() {cout <<"msg";}

Jun 9, 2010 at 6:36pm
Declarations of variables and functions at file scope are external by default.
Jun 9, 2010 at 7:58pm
Declarations of variables [...] at file scope are external by default.
That doesn't sound right. If you declare an object as not explicitly extern in a header, you get duplicate definition errors. That's not the case with functions.

1
2
3
4
5
6
7
8
9
int a;
int a;
extern int b;
extern int b;

void f();
void f();
extern void g();
extern void g();
Jun 9, 2010 at 8:20pm
int a; isn't just a declaration, it's a definition. Change the linkage to static in the header and you'll see it works fine. The extern in the case of extern int b; works because it is not also defining the variable. If you attempt to use b without defining it somewhere (it need not be defined in the translation unit in which it is being used), you will get a linker error saying b is not defined.

void f(); is a declaration, as is extern void g();. Both must later be defined somewhere (exactly once mind you), else you will get a linker error. This means you can't define it in the header in which it's declared, assuming that header is going to be included in more than 1 .cpp file.

--Rollie
Last edited on Jun 9, 2010 at 8:21pm
Jun 9, 2010 at 8:39pm
isn't just a declaration, it's a definition.
Okay, how do you declare a global without using extern and without also defining it?

Change the linkage to static in the header and you'll see it works fine.
That's something entirely different. You'd be declaring a static global in every translation unit that includes the header, such that changes made to it in one file are not reflected in the other files.
For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//0.cpp
#include <iostream>

static int a;
int f();

int main(){
	a=10;
	std::cout <<f()<<std::endl;
	return 0;
}
//1.cpp
static int a;

int f(){
	return a;
}
Last edited on Jun 9, 2010 at 8:40pm
Jun 9, 2010 at 9:37pm
I don't believe you can. If I have a global variable (i.e., there is only one in the whole program), which can only be defined a single time. Assume "foo.h" is included in "foo.cpp" and "main.cpp", with a global variable declared as you describe. Where is it defined: "foo.cpp" or "main.cpp"? It can't be both given the one definition rule, and the variable cannot be linked with the definition from another translation unit without external linkage, so it would be guaranteed that in either "main.cpp" or "foo.cpp", your global variable would be undefined.

--Rollie
Jun 9, 2010 at 9:49pm
Declarations of variables [...] at file scope are external by default.


I agree with helios on this...
Jun 9, 2010 at 9:51pm
Then I was right. Data declarations are non-extern by default.
Jun 9, 2010 at 10:01pm
That doesn't sound right. If you declare an object as not explicitly extern in a header, you get duplicate definition errors. That's not the case with functions.

I agree with this, but unless I'm missing something, I was under the impression that global variables had external linkage by default and (in C) you may use the static keyword to make them module-scope (I assume this is the same as internal linkage).

Do I have external and internal mixed up or something?
Last edited on Jun 9, 2010 at 10:01pm
Jun 9, 2010 at 10:25pm
@moorecm - I agree with that as well, iff that header is used in more than one compilation unit, and you don't specify static or extern.

http://stackoverflow.com/questions/95890/what-is-a-variables-linkage-and-storage-specifier

Try this:

myheader.cpp
 
void foo();


main.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include "myheader.h"

using std::cout;
using std::endl;

int myVar;

int main()
{	
        myVar = 5;
        foo();
	cout << "in main, myVar is " << myVar << endl;
	return 0;
}


myheader.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include "myheader.h"

using std::cout;
using std::endl;

int myVar;

void foo()
{
	cout << "In myheader, myvar = " << myVar << endl;
        myVar = 4;
}


You'll get linker errors when you try to link these, because myVar has external linkage, and is therefore visible across all translation units. If you change myheader.cpp to declare myVar as 'extern int myVar;' (which is only a declaration, not a definition), it works as you expect.

I think Incubbus had it right in their original response to this thread.

--Rollie
Last edited on Jun 9, 2010 at 10:28pm
Jun 9, 2010 at 10:29pm
This is the part of my understanding that I'm starting to question:

Does
has external linkage
really mean
is [...] visible across all translation units
or are these things independent of one another?
Last edited on Jun 9, 2010 at 10:32pm
Jun 9, 2010 at 10:41pm
So, what exactly does "external declaration" in
Declarations of variables [...] at file scope are external by default.
mean? That the symbol has global scope, or that the symbol may be defined in a separate translation unit? If the former, the sentence is almost meaningless, because all things put in global scope have global scope by default (duh).
Last edited on Jun 9, 2010 at 10:42pm
Jun 9, 2010 at 11:43pm
Because two people agree with each other does not mean it´s right^^...

Here is a small part of an c++ standard draft:


4 For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible,23) 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.

5 If the declaration of an identifier for a function has no storage-class specifier, its linkage is determined exactly as if it were declared with the storage-class specifier extern. If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external.


http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf page 30f
Last edited on Jun 9, 2010 at 11:47pm
Jun 9, 2010 at 11:55pm
Because two people agree with each other does not mean it´s right^^...
If that's a reply to http://www.cplusplus.com/forum/general/24904/#msg132013 , firedraco posted while I was writing my post. I was replying to http://www.cplusplus.com/forum/general/24904/#msg132008 .

If the declaration of an identifier for a function has no storage-class specifier, its linkage is determined exactly as if it were declared with the storage-class specifier extern.
If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external.
Is there any difference between these two statements? The phrasing would seem to imply so, but I can't find it.
Jun 10, 2010 at 9:42am
closed account (z05DSL3A)
It is no wonder that everyone is confused with all the misuse of terms and imprecise statements going on.

Declarations of variables and functions at file scope are external by default.

external what by default?

Change the linkage to static...

There is no static linkage...

I know I'm being pedantic, but the more you misuse terms the more the misuse get passed on to the 'next generation'.

To specifically address the question asked, non-member functions have the storage class extern by default.
So:
1
2
3
4
5
6
7
8
9
extern void msg() 
{ 
    std::cout <<"msg";
}

int main()
{
    msg();
}

is the same as
1
2
3
4
5
6
7
8
9
10
void msg()
{ 
    std::cout <<"msg";
}


int main()
{
    msg();
}



Last edited on Jun 10, 2010 at 2:59pm
Topic archived. No new replies allowed.