Undefined reference when using extern on a c++ object, but not integral type - c++

I'm getting undefined reference errors when trying to use extern on a c++ object. It doesn't appear to happen with integral types. What am I missing?! This code below replicates the problem:
file1.cpp:
#include <string>
const std::string s("test");
int i = 99;
int main()
{
extern void Test();
Test();
}
file2.cpp:
#include <iostream>
#include <string>
extern const std::string s;
extern int i;
void Test()
{
std::cout << s << std::endl;
std::cout << i << std::endl;
}
if i comment out the usage of the 's' std::string variable, the linking errors go away.
There are other questions on SO similar to this, but they all seem to be related to people not defining the variable, which I am!

It's the const on std::string, it gives s internal linkage. Quote from [3.5 Program and linkage]:3:
A name having namespace scope (3.3.6) has internal linkage if it is
the name of
— a variable that is explicitly declared const or constexpr and
neither explicitly declared extern nor previously declared to have
external linkage; or

If you remove const, it works in vc++, and if you define them both extern const, it also works.
// file1.cpp
extern const std::string s("test");
extern const int i = 99;
// file2.cpp
extern const std::string s;
extern const int i;
If you remove any 'extern' from file1.cpp, it can't compile. If the variables are defined const, you can remove 'extern' from file1.cpp.

Related

skipping extern for const global still works fine

It is said that for const variables to be referred from outside(i.e. to have external linkage), extern keyword is mandatory. So:
const int f = 3; // Definition of f with internal linkage (due to const)
extern const int g; // Declaration of g with external linkage
If that is correct then how does the following still work fine:
In s1.cpp I have declared and initialized const int a=9 without extern:
s1.cpp
#include<iostream>
#include"h1.h"
using namespace std;
//This is a global variable
const int a=9; // No Extern here
int main()
{
cout<<a;
something();
return 0;
}
h1.h
#ifndef H1_H
#define H1_H
extern const int a; //this extern is anyways required
void something();
#endif
But here is s2.cpp i can still access a without any problem.
s2.cpp
#include<iostream>
#include"h1.h"
using namespace std;
void something()
{
cout<<"Inside something its : "<<a; //No problem here. Why?
}
Can someone please clarify?
I ran it on linux
gcc version 4.4.6 20120305 (Red Hat 4.4.6-4) (GCC)
Compiled as :
g++ s1.cpp s2.cpp -o out
Output as :
9Inside something its : 9indlin1738!
This is because you included h1.h in s1.cpp, so (concerning your question) you have something like:
extern const int a;
const int a = 9;
Which means that a is declared to have external linkage and is then defined and initialized here, so a is thus visible in the other module s2.cpp which only includes h1.h:
extern const int a;

repeated extern declarations of qualified identifiers C++

Why is it that qualified names cannot be re-declared inside functions?
The following code fails to compile (in MSVC2015 and clang)
int i;
namespace N
{
int j;
}
void foo()
{
extern int i;
extern int i;
extern int N::j;
extern int N::j;
}
int main()
{
return 0;
}
However, if we move the two lines extern int N::j; to just before void foo() then the code compiles fine.
UPDATE It is noteworthy that
repeated declarations of unqualified names do work,
both ::i and ::N::j were already defined in their respective declarations,
::N::j is not visible to foo
the grammar does allow extern int ::N::j and it is not a definition
the following code also fails (thank to T.C. for pointing this out)
.
int i;
void foo()
{
extern int ::i;
}
the following code works in MSVC but it gives a warning in clang
.
int i;
extern int ::i;
T.C. directed me to [dcl.meaning]p1
… When the declarator-id is qualified, the declaration shall refer to a previously declared member of the class or namespace to which the qualifier refers (or, in the case of a namespace, of an element of the inline namespace set of that namespace (7.3.1)) or to a specialization thereof …
It seems to me that this is a case where the standard is not faithfully represented by the implementations.
It is the namespace member definition vs. declaration issue here. Please see C++11 spec:
7.3.1.2 Namespace member definitions [namespace.memdef]
1 Members (including explicit specializations of templates (14.7.3)) of a
namespace can be defined within that namespace.
[ Example: namespace X
{ void f() { / ... / } } —end example ]
2 Members of a named
namespace can also be defined outside that namespace by explicit
qualification (3.4.3.2) of the name being defined, provided that the
entity being defined was already declared in the namespace and the
definition appears after the point of declaration in a namespace that
encloses the declaration’s namespace.
Therefore, the revised code below compiles.
int i;
namespace N
{
int j;
void foo()
{
extern int i;
extern int j;
}
}
void foo()
{
extern int i;
using namespace N;
extern int j;
}
int main()
{
return 0;
}
Here is a generic example of using extern with namespace:
In one CPP file:
namespace N
{
int j;
}
In its header file:
namespace N
{
extern int j;
}
Update:
More on extern, namespace, declaration and definition
The :: scope resolution operator cannot be use for declaration. It may be used for definition. Using :: for extern declaration would be ill-formed.
Please see C++11 spec:
7.5 Linkage specifications [dcl.link]
... ...
4 Linkage specifications nest. When linkage specifications nest, the innermost
one determines the language linkage. A linkage specification does not
establish a scope. A linkage-specification shall occur only in
namespace scope (3.3). In a linkage-specification, the specified
language linkage applies to the function types of all function
declarators, function names with external linkage, and variable names
with external linkage declared within the linkage-specification.
3.3.6 Namespace scope [basic.scope.namespace]
1 The declarative region of a namespace-definition is its namespace-body. …
// Compiled with VC2013.
// extern int ::i; // error C2039: 'i' : is not a member of '`global namespace''
extern int i; // declaration
int i; // definition
namespace N
{
extern int j; // declaration
}
int N::j; // definition
namespace N
{
// int j; // definition
}
void foo()
{
// extern int ::i; // fatal error C1506: unrecoverable block scoping error
extern int i; // declaration
// extern int N::j; // error C2086: 'int N::j' : redefinition
}
int main()
{
return 0;
}

How to declare constexpr extern?

Is it possible to declare a variable extern constexpr and define it in another file?
I tried it but the compiler gives error:
Declaration of constexpr variable 'i' is not a definition
in .h:
extern constexpr int i;
in .cpp:
constexpr int i = 10;
no you can't do it, here's what the standard says (section 7.1.5):
1 The constexpr specifier shall be applied only to the definition of a
variable or variable template, the declaration of a function or
function template, or the declaration of a static data member of a
literal type (3.9). If any declaration of a function, function
template, or variable template has a constexpr specifier, then all its
declarations shall contain the constexpr specifier. [Note: An explicit
specialization can differ from the template declaration with respect
to the constexpr specifier. Function parameters cannot be declared
constexpr. — end note ]
some examples given by the standard:
constexpr void square(int &x); // OK: declaration
constexpr int bufsz = 1024; // OK: definition
constexpr struct pixel { // error: pixel is a type
int x;
int y;
constexpr pixel(int); // OK: declaration
};
extern constexpr int memsz; // error: not a definition
C++17 inline variables
This awesome C++17 feature allow us to:
conveniently use just a single memory address for each constant
store it as a constexpr
do it in a single line from one header
main.cpp
#include <cassert>
#include "notmain.hpp"
int main() {
// Both files see the same memory address.
assert(&notmain_i == notmain_func());
assert(notmain_i == 42);
}
notmain.hpp
#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP
inline constexpr int notmain_i = 42;
const int* notmain_func();
#endif
notmain.cpp
#include "notmain.hpp"
const int* notmain_func() {
return &notmain_i;
}
Compile and run:
g++ -c -o notmain.o -std=c++17 -Wall -Wextra -pedantic notmain.cpp
g++ -c -o main.o -std=c++17 -Wall -Wextra -pedantic main.cpp
g++ -o main -std=c++17 -Wall -Wextra -pedantic main.o notmain.o
./main
GitHub upstream.
The C++ standard guarantees that the addresses will be the same. C++17 N4659 standard draft
10.1.6 "The inline specifier":
6 An inline function or variable with external linkage shall have the same address in all translation units.
cppreference https://en.cppreference.com/w/cpp/language/inline explains that if static is not given, then it has external linkage.
See also: How do inline variables work?
Tested in GCC 7.4.0, Ubuntu 18.04.
What you probably want is extern and constexpr initialization, e.g.:
// in header
extern const int g_n;
// in cpp
constexpr int g_n = 2;
This is support though in Visual Studio 2017 only through conformance mode:
/Zc:externConstexpr (Enable extern constexpr variables)
constexpr definition of extern const variable
No. Extern constexpr does not make any sense. Please read http://en.cppreference.com/w/cpp/language/constexpr
i.e. the bit
it must be immediately constructed or assigned a value.
I agree with 'swang' above, but there is a consequence. Consider:
ExternHeader.hpp
extern int e; // Must be extern and defined in .cpp otherwise it is a duplicate symbol.
ExternHeader.cpp
#include "ExternHeader.hpp"
int e = 0;
ConstexprHeader.hpp
int constexpr c = 0; // Must be defined in header since constexpr must be initialized.
Include1.hpp
void print1();
Include1.cpp
#include "Include1.hpp"
#include "ExternHeader.hpp"
#include "ConstexprHeader.hpp"
#include <iostream>
void print1() {
std::cout << "1: extern = " << &e << ", constexpr = " << &c << "\n";
}
Include2.hpp
void print2();
Include2.cpp
#include "Include2.hpp"
#include "ExternHeader.hpp"
#include "ConstexprHeader.hpp"
#include <iostream>
void print2() {
std::cout << "2: extern = " << &e << ", constexpr = " << &c << "\n";
}
main.cpp
#include <iostream>
#include "Include1.hpp"
#include "Include2.hpp"
int main(int argc, const char * argv[]) {
print1();
print2();
return 0;
}
Which prints:
1: extern = 0x1000020a8, constexpr = 0x100001ed0
2: extern = 0x1000020a8, constexpr = 0x100001ed4
IE the constexpr is allocated twice whereas the extern is allocated once.
This is counterintuitive to me, since I 'expect' constexpr to be more optimized than extern.
Edit: const and constexpr have the same behaviour, with regard to allocation, therefore from that point of view the behaviour is as expected. Though, as I said, I was surprised when I came across the behaviour of constexpr.
Yes it somewhat is...
//===================================================================
// afile.h
#ifndef AFILE
#define AFILE
#include <cstddef>
#include <iostream>
enum class IDs {
id1,
id2,
id3,
END
};
// This is the extern declaration of a **constexpr**, use simply **const**
extern const int ids[std::size_t(IDs::END)];
// These functions will demonstrate its usage
template<int id> void Foo() { std::cout << "I am " << id << std::endl; }
extern void Bar();
#endif // AFILE
//===================================================================
// afile.cpp
#include "afile.h"
// Here we define the consexpr.
// It is **constexpr** in this unit and **const** in all other units
constexpr int ids[std::size_t(IDs::END)] = {
int(IDs::id1),
int(IDs::id2),
int(IDs::id3)
};
// The Bar function demonstrates that ids is really constexpr
void Bar() {
Foo<ids[0] >();
Foo<ids[1] + 123>();
Foo<ids[2] / 2 >();
}
//===================================================================
// bfile.h
#ifndef BFILE
#define BFILE
// These functions will demonstrate usage of constexpr ids in an extern unit
extern void Baz();
extern void Qux();
#endif // BFILE
//===================================================================
// bfile.cpp
#include "afile.h"
// Baz demonstrates that ids is (or works as) an extern field
void Baz() {
for (int i: ids) std::cout << i << ", ";
std::cout << std::endl;
}
// Qux demonstrates that extern ids cannot work as constexpr, though
void Qux() {
#if 0 // changing me to non-0 gives you a compile-time error...
Foo<ids[0]>();
#endif
std::cout << "Qux: 'I don't see ids as consexpr, indeed.'"
<< std::endl;
}
//===================================================================
// main.cpp
#include "afile.h"
#include "bfile.h"
int main(int , char **)
{
Bar();
Baz();
Qux();
return 0;
}

Static variables and initialization

I am trying to reach a static variable declared in MyClass.h from MyClass.cpp. But I get following errors.
I made a research but still have no clue why my code does not compile. I use visual studio 2013.
MyClass.h
#ifndef __MyClass_h_
#define __MyClass_h_
class MyClass {
static int x;
public:
static int y;
};
#endif
MyClass.cpp
#include "MyClass.h"
void MyClass::sor() (const string& var1, const unsigned count) const {
// What goes here? See below for what I have tried
}
So, if I use:
int MyClass::x=8;
This says int MyClass::x redefinition and MyClass::x 'MyClass::x' : definition or redeclaration illegal in current scope
If I use:
MyClass::x=8;
This gives the error 1 unresolved external.
If I use:
MyClass::y=8;
This also gives the error 1 unresolved external.
If I use:
int MyClass::y=8;
This says int MyClass::y redefinition and 'MyClass::y' : definition or redeclaration illegal in current scope
You need to understand you don't have a static variable in a header, how other answers suggest. You have a static member of a class, which is perfectly fine.
In order to access it you write: MyClass::x. You need to initialize it also.
Unrelated to the static member, you need to declare the method also:
header:
#ifndef __MyClass_h_
#define __MyClass_h_
class MyClass {
static int x;
public:
static int y;
void sor() (const string& var1, const unsigned count) const;
};
#endif
source file:
#include "MyClass.h"
int MyClass::x = 0; // intialization
void MyClass::sor() (const string& var1, const unsigned count) const {
MyClaxx::x = 11; // access it
}
You have a declaration for the static variable but don't have the definition for it. In order to use static class members you should define them in the corresponding translation unit. You can't do it in the header file because it will violate ODR(one definition rule) so you should define it in the .cpp file to confrom the aforementioned rule.
So you have to put int MyClass::x = 0; in your cpp file in global scope(or under the namespace if you have one) to get it working. Note, that you could use whatever value insted of 0 or even didn't provide any(in this case it will be 0 anyway, due to special treatment of global(static) variables.)
When static variable is declared in a header file is its scope limited to .h file or across all units.
Refer here for source
This is simple. When you declare a static variable in a header file, it's scope is limited to header file. When you going to use that static variable in a .cpp file you getting an error like this. It is because you didn't give the definition of the static variable. So in any of the .cpp file you need to give the definition of static variable. ex :
.h file
class MyClass {
static int x;
.....
}
Top of the .cpp file you should define the static variable like this.
#include "MyClass.h"
int MyClass::x = 0 ;
void MyClass::sor() (const string& var1, const unsigned count) const {
MyClass::x = 8 ; // you can access without any issue
}

Difference between declaration of function with extern and without it

There is such code:
#include <iostream>
extern void fun();
int main(){
fun();
return 0;
}
void fun(){ std::cout << "Hello" << std::endl; }
Is there some difference between declarations:
extern void fun();
void fun();
? Code above behaves the same with extern and without extern keyword.
Function declarations do have external linkage by default, so adding the extern keyword to a function declaration makes no difference, it is redundant.
The difference between the two statements is this:
extern void fun();
tells the compiler and linker to look in another file when the code in this file refers to fun( ), perhaps by calling fun( ); This production is called a "declaration."
void fun ( ) {
...
}
Defines the function fun ( ) and, because it's defined in this file, obviates the need for the linker to look for the function elsewhere.
There's no harm in declaring the function extern: the linker does the right thing.