static, extern, non-static - what does all this mean?

Hello,

I am a beginner with C++ and am having real hard time understanding various C++ features such as static, non-static, extern and stuff. I have a bigger program and recently introduces a static member to access globally. The problems started from there. So I made this simple project which did not compile. I am seeking help to explain what the problem is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
//Calc1.h

#ifndef CALC1_H_INCLUDED
#define CALC1_H_INCLUDED

#pragma once

#include <windows.h>

class Calc1
{
public:
  static void Sub1();
  static void Sub2(int Num);
};


#endif // CALC1_H_INCLUDED

//Data1.h

#ifndef DATA1_H_INCLUDED
#define DATA1_H_INCLUDED

#pragma once

namespace Data1
{

    static const long Constant1=255;
    static const long Constant2=200;

    char StringName[Constant1];
    double Numbers[Constant2];

    long Long1;
    long Long2;

}
#endif // DATA1_H_INCLUDED

//Calc1.cpp

#include <string>
#include <iostream>
#include <stdio.h>
#include "Data1.h"
#include "Calc1.h"

using namespace std;
using namespace Data1;

void Sub1(){

  int x;
  int y;

  int z;

  z = x+y;

}

void Sub2(int Num){

 strcpy(StringName,"hmx.bnc");

 Numbers[0] = 4.56;
 Numbers[1] = 0.8367;

 Long1 = 3;
 Long2 = 5;

}

//main.cpp

#include <iostream>
#include <stdio.h>
#include "Data1.h"
#include "Calc1.h"

using namespace std;
//using namespace Data1;

int main()
{
    int Number;

    Number = 3;

    Calc1::Sub2(Number);

    cout << "Hello world!" << endl;
    return 0;
}


I get the following error when I comppile in MinGW using Code:;blocks on a windows 7 machine.

I would appreciate your help.

1
2
3
4
5
6
7
8
9
10
C:\C++\StaticVariable\Calc1.cpp||In function 'void Sub1()':|
C:\C++\StaticVariable\Calc1.cpp|24|warning: variable 'z' set but not used [-Wunused-but-set-variable]|
C:\C++\StaticVariable\Calc1.cpp|26|warning: 'x' is used uninitialized in this function [-Wuninitialized]|
C:\C++\StaticVariable\Calc1.cpp|26|warning: 'y' is used uninitialized in this function [-Wuninitialized]|
obj\Debug\main.o||In function `main':|
C:\C++\StaticVariable\main.cpp|10|multiple definition of `Data1::StringName'|
obj\Debug\Calc1.o:C:\C++\StaticVariable\Calc1.cpp|19|first defined here|
obj\Debug\main.o:main.cpp|| undefined reference to `Calc1::Sub2(int)'|
||=== Build finished: 3 errors, 3 warnings (0 minutes, 1 seconds) ===|
 

Regards
SP
The extern keyword is used when you are using global variables. You never actually use it, though, because you never actually use global variables.

static has two uses - if you see a static function and it is not part of a class, then it was probably written before the use of static like this was deprecated. It means the same thing as writing the function inside an anonymous namespace; it is only visible to that source file and no others.

If you see a static member function or member variable in a class, then that means it is associated with the class and not any one instance. You can access it with NameOfClass::NameOfMember.

All other members in a class are non-static by default, which means they are associated with specific instances of the class. You access them with name_of_instance.NameOfMember.



As for the errors and warnings you are getting, look at the actual lines your compiler is telling you about:
C:\C++\StaticVariable\Calc1.cpp||In function 'void Sub1()':|
C:\C++\StaticVariable\Calc1.cpp|24|warning: variable 'z' set but not used [-Wunused-but-set-variable]|
C:\C++\StaticVariable\Calc1.cpp|26|warning: 'x' is used uninitialized in this function [-Wuninitialized]|
C:\C++\StaticVariable\Calc1.cpp|26|warning: 'y' is used uninitialized in this function [-Wuninitialized]|
53
54
55
56
57
58
59
60
61
62
void Sub1(){

  int x; //declared, not initialized
  int y; //declared, not initialized

  int z; //declared, not inisialized

  z = x+y; //using x and y which have not been initialized
//not using z despite setting it
}
Maybe you meant to implement void Calc1::Sub1(){}? And the same for void Calc1::Sub2(int Num){}

C:\C++\StaticVariable\main.cpp|10|multiple definition of `Data1::StringName'|
obj\Debug\Calc1.o:C:\C++\StaticVariable\Calc1.cpp|19|first defined here|
Not sure about this, I can't see it in your code. Maybe you were trying to use a global variable and forgot to fully erase it when you realized how bad they are?

obj\Debug\main.o:main.cpp|| undefined reference to `Calc1::Sub2(int)'|
You never define Calc1::Sub2, see above.
Last edited on
LB wrote:
if you see a static function and it is not part of a class, then it was probably written before the use of static like this was deprecated. It means the same thing as writing the function inside an anonymous namespace; it is only visible to that source file and no others.
This usage has been undeprecated in C++11.
Oh? What for? I was not aware of this - is it so different from an anonymous namespace?
LB & Peter,

Thanks for yout tips. I changed the definition of Sub1 and Sub2 as Calc1::Sub1 and Calc1::Sub2.

I understood the warnings, but cannot fingure out the multiple definition error. I just made this program to post in the forum. So what you see is a complete program that I am having.
Ah, I see why it's giving you a multiple definition error.
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//Data1.h

#ifndef DATA1_H_INCLUDED
#define DATA1_H_INCLUDED

#pragma once

namespace Data1
{

    static const long Constant1=255;
    static const long Constant2=200;

    char StringName[Constant1];
    double Numbers[Constant2];

    long Long1;
    long Long2;

}
#endif // DATA1_H_INCLUDED 
These are all definitions, which means they can only be in one .cpp file. With your code, these definitions are being included in multiple .cpp files, which is causing multiple definition problems.

The most obvious way to fix this is to not use global variables, but if you're required by some school assignment to use them because your professor hasn't kept up with the latest good practice in C++ in a long time, then you have to use the extern keyword in headers. Example:
1
2
3
4
5
6
7
8
9
10
11
//Global.cpp - source file
int GlobalVariablesAreBad = 0; //global variable definition

//Global.hpp - header file
extern int GlobalVariablesAreBad; //global variable declaration

//MyCode.cpp - source file
#include "Global.hpp"

//Main.cpp - source file
#include "Global.hpp" 
Last edited on
LB,

So I made the following modifications; Added a new cpp (Data1.cpp) and modified the Data1.h and the code now looks as this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
\\Data1.h

#ifndef DATA1_H_INCLUDED
#define DATA1_H_INCLUDED

#pragma once

namespace Data1
{

    //extern const long Constant1=255;
   // extern const long Constant2=200;
    extern const long Constant1;
    extern const long Constant2;


    extern char StringName[];
    extern double Numbers[];

    extern long Long1;
    extern long Long2;

};
#endif // DATA1_H_INCLUDED

\\Data1.cpp

    const long Constant1=255;
    const long Constant2=200;

    char StringName[Constant1];
    double Numbers[Constant2];

    long Long1;
    long Long2;


Now I get far more errors:
1
2
3
4
5
6
7
8
9
10
11
12
||=== StaticVariable, Debug ===|
C:\C++\StaticVariable\Calc1.cpp|24|warning: variable 'z' set but not used [-Wunused-but-set-variable]|
obj\Debug\Calc1.o||In function `ZN5Calc14Sub2Ei':|
C:\C++\StaticVariable\Calc1.cpp|37|undefined reference to `Data1::StringName'|
C:\C++\StaticVariable\Calc1.cpp|37|undefined reference to `Data1::StringName'|
C:\C++\StaticVariable\Calc1.cpp|39|undefined reference to `Data1::Numbers'|
C:\C++\StaticVariable\Calc1.cpp|39|undefined reference to `Data1::Numbers'|
C:\C++\StaticVariable\Calc1.cpp|40|undefined reference to `Data1::Numbers'|
C:\C++\StaticVariable\Calc1.cpp|40|undefined reference to `Data1::Numbers'|
C:\C++\StaticVariable\Calc1.cpp|42|undefined reference to `Data1::Long1'|
C:\C++\StaticVariable\Calc1.cpp|43|undefined reference to `Data1::Long2'|
||=== Build finished: 8 errors, 1 warnings (0 minutes, 1 seconds) ===| 


What is causing these? Instead of a direct solution, I would like a reference where I could understand these with concrete examples. i want to learn this stuff. I have done pretty heavy programming in FORTRAN, but am new to this obect oriented field.
Last edited on
Can you post all of your code? And put them in separate [code] tags? It looks lime you haven't even fixed some of the other things I pointed out.
L B,

Here is the complete code as you asked:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//Data1.h

#ifndef DATA1_H_INCLUDED
#define DATA1_H_INCLUDED

#pragma once

namespace Data1
{
    //extern const long Constant1=255;
   // extern const long Constant2=200;
    extern const long Constant1;
    extern const long Constant2;


    extern char StringName[];
    extern double Numbers[];

    extern long Long1;
    extern long Long2;

};
#endif // DATA1_H_INCLUDED 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//Calc1.h

#ifndef CALC1_H_INCLUDED
#define CALC1_H_INCLUDED

#pragma once

#include <windows.h>

class Calc1
{
public:
  static void Sub1();
  static void Sub2(int Num);
};


#endif // CALC1_H_INCLUDED 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//Calc1.cpp

#include <string>
#include <iostream>
#include <stdio.h>
#include "Data1.h"
#include "Calc1.h"

using namespace std;
using namespace Data1;

void Calc1::Sub1(){

  int x;
  int y;

  int z;

  x = 1;
  y = 2;

  z = x+y;

}

void Calc1::Sub2(int Num){

using namespace Data1;

 strcpy(StringName,"hmx.bnc");

 Numbers[0] = 4.56;
 Numbers[1] = 0.8367;

 Long1 = 3;
 Long2 = 5;

}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Data1.cpp

#include "Data1.h"

using namespace Data1;

    const long Constant1=255;
    const long Constant2=200;

    char StringName[Constant1];
    double Numbers[Constant2];

    long Long1;
    long Long2;


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//main.cpp

#include <iostream>
#include <stdio.h>
#include "Data1.h"
#include "Calc1.h"

using namespace std;
//using namespace Data1;

int main()
{
    int Number;

    Number = 3;

    Calc1::Sub2(Number);

    cout << "Hello world!" << endl;
    return 0;
}


This the complete code.
Ah, in Data1.cpp the variables need to actually be inside a
1
2
3
4
namespace Data1
{
    //
}
declaration. Or you can prefix each variable with Data1::, but I'm sure you know which is less typing.

Your compiler is also warning you that z isn't used for anything in Calc1::Sub1, which is true, but I think you just wanted to use it for testing purposes. If so, just do a simple output with std::cout rather than some random code like that.
Topic archived. No new replies allowed.