global const variable definition - access through extern in c++ - c++

I read some answers about this topic, but I am still not sure:
In C++ a global const variable definition is automatically static. However I can access it from another cpp-file through extern:
// module.cpp
const int i = 0;
and
// main.cpp
extern const int i;
int main ()
{
if (i > 10)
return 0;
else
return 1;
}
Why is this possible (accessing an object with internal linkage from another module)? Normally I should be forced to define i as extern const int i = 0 in module.cpp, to have an explicitely global but non-static const, or?
In comparison, this is not possible:
// module.cpp
static int i = 0;
and
// main.cpp
extern int i;
int main ()
{
i = 10; // but read-only access like (i > 10) would be possible!
return 0;
}
So is the answer that: yes, you can access internal linked objects from other modules, but only for read (so always with const)?
Edit:
Sorry, but I made a mistake: in my original code I just tried an expression without effect (in both examples):
extern const int i; // or extern int i for second example
int main ()
{
i>10;
return 0;
}
I thought, that it behaves the same, as if program flow or data was dependent of this expression, but in fact it does not! The compiler seems to just cut out this effectless expression, so that the linker does not see it! So all is alright: in the first example i must be indeed defined extern const int i = 0 in module.cpp, and in the second example i cannot be accessed at all (unless in effectless expression). Compiler is VC++2010.
Edit2:
However, now I don't understand why this is possible:
// module.cpp
extern const int i = 0;
and
// main.cpp
int i = 99;
int main ()
{
bool b = i>10;
return 0;
}
i have both external linkage. But no error. When in module.cpp I define int i = 0, then error (multiple symbols). Why?

As for me it looks like a compiler bug. Constant variable i is not defined It is only declared in main.cpp. As for variable i in module.cpp then it has internal linkage and shall not be accessible outside the module.
Relative to your addition to the original post then the compiler has nothing common with this situation. It is linker that checks whether there are duplicate external symbols. I think it decided that if one variable has qualifier const and other has no it then there are two different variables. I think that it is implementation defined whether the linker will issue an error or not. Moreover it can have some options that could control the behaviour of the linker in such situations.

Related

Why the singleton initialization failed (link error) [duplicate]

Very simply put:
I have a class that consists mostly of static public members, so I can group similar functions together that still have to be called from other classes/functions.
Anyway, I have defined two static unsigned char variables in my class public scope, when I try to modify these values in the same class' constructor, I am getting an "unresolved external symbol" error at compilation.
class test
{
public:
static unsigned char X;
static unsigned char Y;
...
test();
};
test::test()
{
X = 1;
Y = 2;
}
I'm new to C++ so go easy on me. Why can't I do this?
If you are using C++ 17 you can just use the inline specifier (see https://stackoverflow.com/a/11711082/55721)
If using older versions of the C++ standard, you must add the definitions to match your declarations of X and Y
unsigned char test::X;
unsigned char test::Y;
somewhere. You might want to also initialize a static member
unsigned char test::X = 4;
and again, you do that in the definition (usually in a CXX file) not in the declaration (which is often in a .H file)
Static data members declarations in the class declaration are not definition of them.
To define them you should do this in the .CPP file to avoid duplicated symbols.
The only data you can declare and define is integral static constants.
(Values of enums can be used as constant values as well)
You might want to rewrite your code as:
class test {
public:
const static unsigned char X = 1;
const static unsigned char Y = 2;
...
test();
};
test::test() {
}
If you want to have ability to modify you static variables (in other words when it is inappropriate to declare them as const), you can separate you code between .H and .CPP in the following way:
.H :
class test {
public:
static unsigned char X;
static unsigned char Y;
...
test();
};
.CPP :
unsigned char test::X = 1;
unsigned char test::Y = 2;
test::test()
{
// constructor is empty.
// We don't initialize static data member here,
// because static data initialization will happen on every constructor call.
}
in my case, I declared one static variable in .h file, like
//myClass.h
class myClass
{
static int m_nMyVar;
static void myFunc();
}
and in myClass.cpp, I tried to use this m_nMyVar. It got LINK error like:
error LNK2001: unresolved external symbol "public: static class...
The link error related cpp file looks like:
//myClass.cpp
void myClass::myFunc()
{
myClass::m_nMyVar = 123; //I tried to use this m_nMyVar here and got link error
}
So I add below code on the top of myClass.cpp
//myClass.cpp
int myClass::m_nMyVar; //it seems redefine m_nMyVar, but it works well
void myClass::myFunc()
{
myClass::m_nMyVar = 123; //I tried to use this m_nMyVar here and got link error
}
then LNK2001 is gone.
Since this is the first SO thread that seemed to come up for me when searching for "unresolved externals with static const members" in general, I'll leave another hint to solve one problem with unresolved externals here:
For me, the thing that I forgot was to mark my class definition __declspec(dllexport), and when called from another class (outside that class's dll's boundaries), I of course got the my unresolved external error.
Still, easy to forget when you're changing an internal helper class to a one accessible from elsewhere, so if you're working in a dynamically linked project, you might as well check that, too.
When we declare a static variable in a class, it is shared by all the objects of that class. As static variables are initialized only once they are never initialized by a constructor. Instead, the static variable should be explicitly initialized outside the class only once using the scope resolution operator (::).
In the below example, static variable counter is a member of the class Demo. Note how it is initialized explicitly outside the class with the initial value = 0.
#include <iostream>
#include <string>
using namespace std;
class Demo{
int var;
static int counter;
public:
Demo(int var):var(var){
cout<<"Counter = "<<counter<<endl;
counter++;
}
};
int Demo::counter = 0; //static variable initialisation
int main()
{
Demo d(2), d1(10),d3(1);
}
Output:
Count = 0
Count = 1
Count = 2
In my case, I was using wrong linking.
It was managed c++ (cli) but with native exporting. I have added to linker -> input -> assembly link resource the dll of the library from which the function is exported. But native c++ linking requires .lib file to "see" implementations in cpp correctly, so for me helped to add the .lib file to linker -> input -> additional dependencies.
[Usually managed code does not use dll export and import, it uses references, but that was unique situation.]

Does static function hide non-static function with the same name?

I tried to look this up, but did not find it anywhere. So here's the question:
Static functions in C/C++ can be used to "make them invisible to the outer world". Great, when having two same-named static functions in two different compiled units (.c files), it makes me sure that I call the right one. But can I also be sure that I call my local static function when there exists a same-named non-static function somewhere in the project or libraries? That is, does the static function locally hide the non-static one?
Sure I can test it (and I did) but I want to know whether this behaviour has fixed definition in C/C++. Thanks.
Edit: Simplified example code which caused unexpected behaviour to me. The question is about the fix of the problem (suppose I cannot change the library).
In mylib.c:
#include "mylib.h"
int send(void * data, int size);
...
int send(void * data, int size) {
return send_message(queueA, data, size);
}
void libfunc(void) {
send(str, strlen(str));
}
In mylib.h:
// only libfunc is declared here
void libfunc(void);
In myprog.c:
#include "mylib.h"
int send(void * data, int size);
...
int send(void * data, int size) {
return send_message(queueB, data, size);
}
void progfunc(void) {
// expected to send a message to queueB
// !!! but it was sent to queueA instead !!!
send(str, strlen(str));
}
Compiled mylib.c + further files -> mylib.a
Compiled myprog.c -> myprog.o
Linked myprog.o + mylib.a -> myprog
You'd get a compilation error because functions have default external linkage, thus the new static function would result in a conflict of linkage specifiers.
If the declaration of the non-static function isn't visible, the static one will be called:
void foo(); //external linkage
static void foo() {}; //internal linkage and error
It does not hide functions with same name declared in the same scope. However you may not have a function with the same signature declared as having internal and external linkage.

Class declaration in a header file and static variables

Noob question, but would like to understand the following:
Imagine I have a multifile project. I'm specifying a class in a header file to be shared among all the files in the project, and I write this : static int test = 0; and in the next line this: static const int MAX = 4;
The first one would be an error trying to compile because of the one definition rule. But the second one will compile without errors. Why?
From what I understand, both have the same properties: whole execution storage duration, class scope and no linkage.
Any help?
EDIT: testing an external constant declaration in a header: extern const int MAX = 4; to force external linkage produced the expected error. So I don't understand why with the variable it gives me the error and with the constant it doesn't.
Try
static const int test = 0;
I've sometimes noticed compiler errors with the immediate initialization of static const variables in the header file. You can always use the declaration in the header
class MyClass
{
// ...
static const int test;
// ...
}
and initialize it in the corresponding .cpp file
const int MyClass::test = 0;
This should work properly with any other types than int as well.
Integer constants in C++ don't actually occupy any space in the object and don't act like variables in general. Think about them more like numbers that are given names in this particular context.

Static function access in other files

Is there any chance that a function defined with static can be accessed outside the file scope?
It depends upon what you mean by "access". Of course, the function cannot be called by name in any other file since it's static in a different file, but you have have a function pointer to it.
$ cat f1.c
/* static */
static int number(void)
{
return 42;
}
/* "global" pointer */
int (*pf)(void);
void initialize(void)
{
pf = number;
}
$ cat f2.c
#include <stdio.h>
extern int (*pf)(void);
extern void initialize(void);
int main(void)
{
initialize();
printf("%d\n", pf());
return 0;
}
$ gcc -ansi -pedantic -W -Wall f1.c f2.c
$ ./a.out
42
It could be called from outside the scope via function pointer.
For example, if you had:
static int transform(int x)
{
return x * 2;
}
typedef int (*FUNC_PTR)(int);
FUNC_PTR get_pointer(void)
{
return transform;
}
then a function outside the scope can call get_pointer() and use the returned function pointer to call transform.
No, unless there's a bug in the compiler. Normally the static function code is not tagged with a name used for exporting the function in the object file, so it is not presented to the linker and it just can't link to it.
This of course only applies to calling the function by name. Other code within the same file can get the function address and pass it into a non-static function in another file and then the function from another file can call your static function.
It cannot be accessed outside a file by it's name. But, you can as well assign it to function pointer and use it wherever you want.
"Accessed"? It depends on what you mean by this term. I assume when you say "static function" you are talking about standalone function declared static (i.e. declared with internal linkage) as opposed to static class member functions in C++, since the latter are obviosly and easily accessible from anywhere.
Now, a standalone function declared static has internal linkage. It cannot be linked to from any other translation unit. Or, putting it differently, it cannot be referred to by name from any other translation unit. If that's what you meant by "access from outside the file scope", then no, it can't be done.
However, if the other translation units somehow get a pointer to that function (i.e. if you somehow allow that pointer to "leak" into the ouside world), then anybody can still call that function by making an idirect call and thus "access" it. For example, if you declare
static void foo_static(void) {
}
extern void (*foo_ptr)(void) = foo_static;
then in any other translation unit the user will be able to do
extern void (*foo_ptr)(void);
foo_ptr();
and the call will go to your foo_static function. I don't know if that kind of access qualifies as "access" in your question.
Following the standard, a static function cannot be accessed outside of the scope of the file by name because it is subject to internal linkage. It's name is not exported, and not provided to the linker. However, it can still be accessed and called by function pointer, like any other function.
Only with trickery. The function is generally not visible to the linker so it won't let you do it.
But, if you provide a function inside the same compilation unit (as the static function) which returns the address of that function:
In main.c:
#inclde <stdio.h>
int (*getGet7(void))(void);
int main (void) {
int (*fn)(void) = getGet7();
printf ("Result is: %d\n", fn());
return 0;
}
In hidden.c:
static int get7 (void) {
return 7;
}
int (*getGet7(void)) (void) {
return get7;
}
This will result in the static function get7 being called.
pax> gcc -o demo main.c hidden.c ; ./demo
Result is: 7
No, the purpose of the keyword static is to limit the scope of the function name to the file.

Unresolved external symbol on static class members

Very simply put:
I have a class that consists mostly of static public members, so I can group similar functions together that still have to be called from other classes/functions.
Anyway, I have defined two static unsigned char variables in my class public scope, when I try to modify these values in the same class' constructor, I am getting an "unresolved external symbol" error at compilation.
class test
{
public:
static unsigned char X;
static unsigned char Y;
...
test();
};
test::test()
{
X = 1;
Y = 2;
}
I'm new to C++ so go easy on me. Why can't I do this?
If you are using C++ 17 you can just use the inline specifier (see https://stackoverflow.com/a/11711082/55721)
If using older versions of the C++ standard, you must add the definitions to match your declarations of X and Y
unsigned char test::X;
unsigned char test::Y;
somewhere. You might want to also initialize a static member
unsigned char test::X = 4;
and again, you do that in the definition (usually in a CXX file) not in the declaration (which is often in a .H file)
Static data members declarations in the class declaration are not definition of them.
To define them you should do this in the .CPP file to avoid duplicated symbols.
The only data you can declare and define is integral static constants.
(Values of enums can be used as constant values as well)
You might want to rewrite your code as:
class test {
public:
const static unsigned char X = 1;
const static unsigned char Y = 2;
...
test();
};
test::test() {
}
If you want to have ability to modify you static variables (in other words when it is inappropriate to declare them as const), you can separate you code between .H and .CPP in the following way:
.H :
class test {
public:
static unsigned char X;
static unsigned char Y;
...
test();
};
.CPP :
unsigned char test::X = 1;
unsigned char test::Y = 2;
test::test()
{
// constructor is empty.
// We don't initialize static data member here,
// because static data initialization will happen on every constructor call.
}
in my case, I declared one static variable in .h file, like
//myClass.h
class myClass
{
static int m_nMyVar;
static void myFunc();
}
and in myClass.cpp, I tried to use this m_nMyVar. It got LINK error like:
error LNK2001: unresolved external symbol "public: static class...
The link error related cpp file looks like:
//myClass.cpp
void myClass::myFunc()
{
myClass::m_nMyVar = 123; //I tried to use this m_nMyVar here and got link error
}
So I add below code on the top of myClass.cpp
//myClass.cpp
int myClass::m_nMyVar; //it seems redefine m_nMyVar, but it works well
void myClass::myFunc()
{
myClass::m_nMyVar = 123; //I tried to use this m_nMyVar here and got link error
}
then LNK2001 is gone.
Since this is the first SO thread that seemed to come up for me when searching for "unresolved externals with static const members" in general, I'll leave another hint to solve one problem with unresolved externals here:
For me, the thing that I forgot was to mark my class definition __declspec(dllexport), and when called from another class (outside that class's dll's boundaries), I of course got the my unresolved external error.
Still, easy to forget when you're changing an internal helper class to a one accessible from elsewhere, so if you're working in a dynamically linked project, you might as well check that, too.
When we declare a static variable in a class, it is shared by all the objects of that class. As static variables are initialized only once they are never initialized by a constructor. Instead, the static variable should be explicitly initialized outside the class only once using the scope resolution operator (::).
In the below example, static variable counter is a member of the class Demo. Note how it is initialized explicitly outside the class with the initial value = 0.
#include <iostream>
#include <string>
using namespace std;
class Demo{
int var;
static int counter;
public:
Demo(int var):var(var){
cout<<"Counter = "<<counter<<endl;
counter++;
}
};
int Demo::counter = 0; //static variable initialisation
int main()
{
Demo d(2), d1(10),d3(1);
}
Output:
Count = 0
Count = 1
Count = 2
In my case, I was using wrong linking.
It was managed c++ (cli) but with native exporting. I have added to linker -> input -> assembly link resource the dll of the library from which the function is exported. But native c++ linking requires .lib file to "see" implementations in cpp correctly, so for me helped to add the .lib file to linker -> input -> additional dependencies.
[Usually managed code does not use dll export and import, it uses references, but that was unique situation.]