What if using extern declaration inside the function? - c++

I've tried the following code and got an error.
int main()
{
//this will cause redefinition error
extern int x;
int x=2;
}
I've seen some answers about extern such as
When to use extern in C++
Defining extern variable in main() vs. globally
and got an concept,but I am still wondering what does the compiler do in this case. Can extern be used(legal) inside some function?
update:
More specifically, since extern int x is just a declaration,why can't I define int x? Does the compiler take extern int x as a definition?

but I am still wondering what does the compiler do in this case. Can extern be used(legal) inside some function?
it can, but you must not redeclare variable as you have in your code. So this is a valid example:
int main()
{
//this will cause redefinition error
extern int x;
x=2;
}
int x;

Of course it can be used, don't define another x inside the function:
int main()
{
extern int x;
x=2;
}

As the others have answered, yes, you can use it in your function as long as you don't declare another variable with that name.
To your question of what the compiler does, dreamlax's answer to the question you linked, handles it pretty well. The compiler doesn't need to do/know anything other than what it's type is so that it knows how it can be used. The linker will see that it's an extern and know that it needs to go find where it is actually declared.
This MSDN link provides more general info on externs and what Microsoft does in VS 2015.

Related

Rules regarding using declarations c++

After reading the accepted answer from this question, I thought I understood why the program failed, since the using directive does not actually declare the entity i in the region. However names introduced by a using declaration can be used just like any other name and acts like a declaration.
With GCC, this fails
#include <iostream>
namespace X { int i = 1; }
using X::i;
int main() {
extern int i;
i = 2;
std::cout<<i;
}
But this is accepted
#include <iostream>
int i;
int main() {
extern int i;
i = 2;
std::cout<<i;
}
Technically, the example you've given does compile, but it fails to link. The issue is the line
extern int i;
What you're telling the compiler/linker here is "there will be a variable i defined somewhere else in the program, so, compiler, don't worry if you can't find the definition. Linker, I expect you to find the definition of i once you have all of the object files and link that in here."
We can see this in action using compiler explorer:
Without the extern declaration
With the extern declaration
In the second case, the declaration of i "shadows" the X::i which is visible at global scope, so we get the instruction
mov DWORD PTR i[rip], 2
whereas without the extern declaration, we get
mov DWORD PTR X::i[rip], 2
though I'm not totally sure on the shadowing part, as neither gcc nor clang warns about that with -Wshadow. In any case, we see now why the second example fails to link: the linker is trying to find the definition of i to use here, and while X::i is defined at global scope, i is not.

Is a extern variable with initialization really a definition?

I know a variable with initialization is a definition no matter if it is extern. However, since extern int x=1; is a definition, why doesn't the compiler throw redefinition error running the following code?
//ok,no error
int x;
extern int x=1;
int main()
{
}
//however,this is an error
extern int x=1;
int x;
int main()
{
}
Why can this happen? Is there any difference?
Update:You are right.When I compile with VS 2013,there is no error.Now I tried with gcc on linux and got an redefinition error just as I expected.
Just as #Bo Persson said,it's all about tentative definition in C. And when I change the file suffix to .c, gcc takes it as a warning rather than an error and it can be compiled.
Firstly, both of your snippets are ill-formed - please use a modern compiler to try them out.
first snippet on wandbox
second snippet on wandbox
When declaring a variable in global scope, it is automatically zero-initialized. This is the reason you're getting a redefinition error - x is already defined to zero.
The following snippet will compile:
extern int x;
int x;
int main()
{
}

Do inline namespace variables have internal linkage? If not, why does the code below work?

This question is directly related to this one. Consider the code:
#include <iostream>
inline namespace N1
{
int x = 42;
}
int x = 10;
int main()
{
extern int x;
std::cout << x; // displays 10
}
It displays 10. If I remove the extern int x; declaration then we get an ambiguity compiler time error
error: reference to 'x' is ambiguous
Question: why does the code work with the extern int x declaration work, and why does it stop working when I remove it? Is it because inline namespace variables have internal linkage?
No. There is no provision in [basic.link] that would cause x to have internal linkage. Specifically, "All other namespaces have external linkage.", and "other" refers to "not unnamed". Perhaps you were thinking of unnamed namespaces?
No, the code works because to avoid breaking existing C code, extern int x; has to work the same way in did in C, in other words creating a local extern to a global namespace (that's all we had in C) variable. Then when you use it later the locally declared extern removes any possible ambiguity.

Is there any possible use of using extern variable in a file that is not included in any other file?

I've encountered many examples on the web, that have extern int x in main.c, where the main function lies.
The only use of extern I'm aware of, is to make a declaration in another file, and use it in another file, after defining it.
Like :
a.h : extern int x;
a.c : int x = 5;
main.c :
#include "a.h" // and start using x
The 1st case seems redundant to me.
So,
Is there any possible use of using an extern variable in a file that is not included in any other file?
extern tells the compiler that x exists in a different module and should be linked from elsewhere. Putting it in main.c directly just avoids pulling in a header (which would be included in-line anyways)
Just like in a header, x still needs to exist in another .c module where it isn't defined extern.
extern variable has basically two functions one is to use the variable in the other file and the other is to access global variables as in the following code.
int x=10;
int main()
{
int x=20;
cout<<x; //refers to x=20
if(x==20)
{
extern int x;
cout<<x; //refers to the global x that is x=10
}
}
Of course. Using extern in a file lets you use that variable in that file. It doesn't have to be included anywhere else.
The use of extern causes the object to have external linkage; to
instantiate a template with a object (and not a value or a type), the
object has to have external linkage (at least in C++03). Most objects
defined in namespace scope have global linkage, but const objects don't.
So you have something like:
template <char const* n>
class Toto { /* ... */ };
char const n1[] = "abc";
Toto<n1> t1; // Illegal...
extern char const n2[] = "xyz";
Toto<n2> t2; // Legal...
It's sort of a special case, but it has led me (once or twice) to use
extern in an unnamed namespace in a source file.

C++ Extern / Multiple Definitions

I am trying to interface to Ada in C++ using externs. What is the difference between these two implementations?
Implementation A
namespace Ada
{
extern "C"
{
int getNumber();
int index;
int value;
}
}
Implementation B
namespace Ada
{
extern "C"
{
int getNumber();
}
extern "C" int index;
extern "C" int value;
}
Both implementations compile just fine. But Impl-A fails to link, I get a multiple definition error for index and value. I'm just trying to understand the differences.
extern "C" only conveys the linking conventions to use for the code within the extern "C" block. Anything in that block will be linked against as if it were pure c. Confusingly, extern int is totally different. It means that you promise there is an actual int named index and an actual int named value somewhere, but they cannot be found here. In your implementation-A the ints are actually not extern in the second sense - the extern "C" only implies that they provide a strict c linking convention.
Same keyword but totally different uses, which is unfortunate since it leads to weird issues like this. Mixing them is legal (obviously), but they don't behave together the way that their name implies.
EDIT
See Charle's response for the true definition of the extern weirdness as defined in the C++ standard.
A linkage-specifier (i.e. extern "C" or extern "C++") applied to a brace enclosed sequence of declarations has no effect on whether the enclosed declarations are definitions or not, however a linkage-specifier applied to a single declaration is treated as an extern specifier for the purposes of determining whether a declaration is also a definition. (7.5 para 7 of C++03)
So:
extern "C" { int a; } // a is declared and defined
extern "C" int a; // a is just a declaration (as if extern int a;)
extern "C" int a = 0; // a is a definition because of the initializer.
I'm not sure why the second works, but you want
namespace Ada
{
extern "C"
{
int getNumber();
extern int index;
extern int value;
}
}
because you only want to declare index and value, not define them. (See this answer for the difference.)