I don't quite understand the concepts behind using the extern and const keywords in C++.
I've read a few related questions on the subject ( see below ), but so far I haven't been able to get a grasp on how to use them together.
Related Questions:
How do I share a variable between source files in C? With extern, but how?
What is the Difference Between a Definition and a Declaration?
What is a Translation ( Compilation ) Unit?
What Exactly is the One Definition Rule in C++?
Ok, take for example the following program code:
dConst.hpp
extern const int NUM_GENERATORS; // Number of generators in power plant
extern const int generatorID[NUM_GENERATORS]; // Generator ID numbers
extern const bool generatorStatus[NUM_GENERATORS]; // Generator Status
vConst.cpp
const int NUM_GENERATORS = 4; // Generators in Power Plant
const int generatorID[NUM_GENERATORS] = // Generator ID numbers
{
23, 57, 49, 106
};
const bool generatorStatus[NUM_GENERATORS] = // Production status ( online? )
{
true, false, false, true
};
main.cpp
#include <iostream>
#include "dConst.hpp"
using std::cout;
using std::cin;
using std::endl;
// ----====< M A I N >====----
int main()
{
for ( int iGenerator = 0; iGenerator < NUM_GENERATORS; iGenerator++ )
{
cout << "Generator ";
cout << generatorID[iGenerator];
if ( generatorStatus[iGenerator] )
cout << "is running." << endl;
else
cout << "is offline!" << endl;
}
cout << "Press ENTER to EXIT:";
cin.get(); // Stop
return 0;
}
I am unable to use NUM_GENERATORS to declare my arrays full of generator ID's and statuses. I've included the external definitions at the top: #include "dConst.hpp. From what I've read ( perhaps not closely enough ) on some of the StackOverflow questions here, the compiler and linker should be able to find the values defined in vConst.cpp, and continue on their merry way.
So why aren't they doing this?
The linker can find it, but the compiler can't, since it is in a different compilation unit. The compiler needs to know the size of the array at compile time, but it will only be known at link time if the constant is declared extern.
Mr. Pollex is exactly right, however I thought I might expand on his answer so that folks looking for this information in the future might have a more complete picture. Often modern IDE's obscure the multiple parts involved in converting source code into executable binary.
Broadly speaking the C/C++ compiler only deals with text files (source files). The compiler reads these files, parses them and outputs object files. Object files contain binary executable sections and symbol sections. The linker then runs to 'link' various binary object files into a single executable. It does this by matching the symbols requested with the symbols available.
In the case you have presented you are using the 'extern' keyword to tell the compiler that the value for the defined symbol is defined in a different object than the one generated by this source. This tells the compiler to generate an object that imports this symbol. The linker then takes care of matching up the imported/exported symbols from the objects. Because of this the value you are looking for isn't available when the compiler runs because it depends on an external symbol from another object (that may not have even been build at that point). There is no way for the compiler to know the value of the symbol, therefore it can't use it.
Related
I just feel weird about how does that work ?
That my first time that I've ever seen that , two c++ files located in the same directory "Test1.cpp,Test2.cpp"
Test1.cpp :
#include <iostream>
void magic();
int main(){
magic();
return 0;
}
Test2.cpp :
#include <iostream>
using namespace std;
void magic(){
cout << "That's not a magic , it's a logical thing.." << endl;
}
As I mentioned above , they are in the same directory , with prototype of 'magic' function.
Now my question is , how does magic work without any inclusion of Test2.cpp ?
Does C++ include it by default ? if that's true , then why do we need to include our classes ? why do we need header file while cpp file can does its purpose ?
In order to obtain an executable from a C++ source code two main phases are required:
compilation phase;
linking phase.
The first one searches only for the signature of the functions and check if the function call is compatible with the found declarations.
The second one searches the implementation of the function among the libraries or objects linked through the options specified through command line of the linker (some compilers can automatically run the linker adding some command line options).
So you need to understand the compiler and linker options in order to understand this process.
The main catch of headers file is simplifying writing of code.
Let's think about next example:
test2.cpp
#include <iostream>
using namespace std;
void my ()
{ magic(); } // here we don't know what magic() is and compiler will complain
void magic(){
cout << "That's not a magic , it's a logical thing.." << endl;
}
This code gives next error:
gaal#linux-t420:~/Downloads> g++ test2.cpp
test2.cpp: In function ‘void my()’:
test2.cpp:6:9: error: ‘magic’ was not declared in this scope
{ magic(); } // here we don't know what magic() is and compiler will complain
^
To avoid this error we need to place declaration of magic() function before definition of my(). So it is good idea to place ALL declarations in one place. Header file is a such place. If we don't use headers, we'll need to paste declaration of magic() function in any cpp-file where it will be used.
I'm new to doing structs, so please bear with me if this turns out to be a dumb question. I have one header file and four .cpp files that all include it. I have a struct called ToDoLista and it has string nameIt and int DeadLine. Then I have the things whose type name I don't know that are like, the Soccer and DropOffMax and stuff.
ToDoLista Soccer, DropOffMax, CookDinner;
Soccer.DeadLine=6;
Soccer.nameIt="SOCCER";
//and so on, for a total of six, 3 ints and 3 strings definitions.
This struct seems to be finnicky if I try to move it around because if it's in the header it's included three times and it wont run due to 'multiply defined' whatever. If I put it in one of my three non-main cpp files, it seems that the struct won't work because some of it has to be defined in main(). So now it's in my main cpp file, but I have functions that use these values, and those functions are in my non-main cpp files, which as far as I know compile before the main one. To get around that, I put the struct declaration in the header, and the definitions in my main (I may have mis-worded that) AND THEN I say 'okay, run the function 'CheckItTwice'.
//MAIN
Soccer.DeadLine=6;
//and so on for all six, like before.
//ok, NOW run the fx.
CheckItTwice(Soccer.Deadline, Soccer.nameIt);
The issue here is that if I tell CheckItTwice to say, cout the string, or the int, it runs the program without errors, but returns nothing in the console where the cout should be, because apparently they haven't been defined yet, as far as the function is concerned. Why is this/do you know a way around this?
In order to avoid the "defined multiply" errors you need to define your struct in a header file, and put a #pragma once or #ifndef...etc block at the top. See this here.
Include the header file in any implementation (cpp) file you plan to use the struct in.
The line
ToDoLista Soccer, DropOffMax, CookDinner;
declares three instances of the struct ToDolista, called Soccer, DropOffMax, and CookDinner. They are not types, they are instances of a type, that type being ToDolista.
I can't comment on the contents of CheckItTwice() as you didn't provide them, but look here for guidance on using cout. You might want to consider passing the struct as one argument to this method, preferrably as a const reference.
Define the struct in your header and #include that header in the cpp files. In the header try adding
#pragma once
at the top of your header file. This is a Microsoft specific extension - documented here
The more portable version is to add
#ifndef _SOME_DEF_
#define _SOME_DEF_
struct ToDoLista {
string namit;
string project;
int status;
int speed;
int difficulty;
int priority;
int deadline;
}
#endif // _SOME_DEF_
Be sure to remove struct definition from the .cpp file.
I got this issue resolved using something I saw while searching desperately online: extern. it seems that if I put the declaraction in the header, the definition in a cpp, and then declare the object again in another cpp but with 'extern' before it, it works like a charm as far as keeping the values from the original definition.
Header.h
struct ToDoLista{
string namit;
string project;
int status;
int speed;
int difficulty;
int priority;
int deadline;
};
Side.cpp
ToDoLista Pushups, Tumblr, Laundry, CleanRoom, CleanHouse, Portfolio;
void CheckItTwice(int staytus, string name){
if(staytus==1){//not on the list
staytus==2;
cout << "hurry up and" << name << " okay?" << endl;
Main.cpp
extern ToDoLista Pushups, Tumblr, Laundry, CleanRoom, CleanHouse, Portfolio;
Pushups.namit = "Push Ups";
Pushups.status = 1;
Pushups.speed = 0;
Pushups.difficulty = 0;
Pushups.priority = 0;
Pushups.project = "Get Fit";
Pushups.deadline = 20131102;
CheckItTwice(Pushups.status,Pushups.namit);
This works for me, and I hope this 'answer' helps someone else.
I have the following two files
//###########
//a.cpp
//###########
#include <iostream>
int main()
{
extern int var; //Why is this allowed?
std::cout << var << std::endl;
var = 99; //Core dump happens here
std::cout << var << std::endl;
return 0;
}
and
//###########
//b.cpp
//###########
extern const int var = 41;
Here, compilation and linking happens without any problem. When I run, I get core dump while trying to set the value of "var" to 99. I want to know why I am allowed to declare a non-const var in a.cpp. Shouldn't the linker fail to link this?
Technically, your program is "incorrect" according to the C++ standard. I'm not sure if it ends up beting "Undefined behaviour" or some other classification of "You shouldn't really be doing this, it's wrong".
However, it's hard for the compiler to convey sufficient information for the linker to spot this type of error, as the linker doesn't really understand "what you are doing" (e.g. writing to a const is not valid, but the linker doesn't understand that the operations are a write - it just knows that "you want the address of var here).
Since you are essentially lying to the compiler, you are doing this to yourself. C and C++ are full of cases where you have to keep yourself honest with the compiler, or things may go horribly wrong, but the compiler doesn't always help you spot these things (often because it's hard to achieve in a reliable way).
See the code, then you would understand what I'm confused.
Test.h
class Test {
public:
#ifndef HIDE_VARIABLE
int m_Test[10];
#endif
};
Aho.h
class Test;
int GetSizeA();
Test* GetNewTestA();
Aho.cpp
//#define HIDE_VARIABLE
#include "Test.h"
#include "Aho.h"
int GetSizeA() { return sizeof(Test); }
Test* GetNewTestA() { return new Test(); }
Bho.h
class Test;
int GetSizeB();
Test* GetNewTestB();
Bho.cpp
#define HIDE_VARIABLE // important!
#include "Test.h"
#include "Bho.h"
int GetSizeB() { return sizeof(Test); }
Test* GetNewTestB() { return new Test(); }
TestPrj.cpp
#include "Aho.h"
#include "Bho.h"
#include "Test.h"
int _tmain(int argc, _TCHAR* argv[]) {
int a = GetSizeA();
int b = GetSizeB();
Test* pA = GetNewTestA();
Test* pB = GetNewTestB();
pA->m_Test[0] = 1;
pB->m_Test[0] = 1;
// output : 40 1
std::cout << a << '\t' << b << std::endl;
char temp;
std::cin >> temp;
return 0;
}
Aho.cpp does not #define HIDE_VARIABLE, so GetSizeA() returns 40, but
Bho.cpp does #define HIDE_VARIABLE, so GetSizeB() returns 1.
But, Test* pA and Test* pB both have member variable m_Test[].
If the size of class Test from Bho.cpp is 1, then pB is weird, isn't it?
I don't understand what's going on, please let me know.
Thanks, in advance.
Environment:
Microsoft Visual Studio 2005 SP1 (or SP2?)
You violated the requirements of One Definition Rule (ODR). The behavior of your program is undefined. That's the only thing that's going on here.
According to ODR, classes with external linkage have to be defined identically in all translation units.
Your code exhibits undefined behavior. You are violating the one definition rule (class Test is defined differently in two places). Therefore the compiler is allowed to do whatever it wants, including "weird" behavior.
In addition to ODR.
Most of the grief is caused by including the headers only in the cpp files, allowing you to change the definition between the compilation units.
But, Test* pA and Test* pB both have member variable m_Test[].
No, pB doesn't have m_Test[] however the TestPrj compilation unit doesn't know that and is applying the wrong structure of the class so it will compile.
Unless you compile in debug with capturing of memory overrun you would most times not see a problem.
pB->m_Test[9] = 1; would cause writing to memory not assigned by pB but may or may not be a valid space for you to write.
Like many people told here, you've violated the so-called One Definition Rule (ODR).
It's important to realize how C/C++ programs are assembled. That is, the translation units (cpp files) are compiled separately, without any connection to each other. Next linker assembles the executable according to the symbols and the code pieces generated by the compiler. It doesn't have any high-level type information, hence it's unable (and should not) to detect the problem.
So that you've actually cheated the compiler, beaten yourself, shoot your foot, whatever you like.
One point that I'd like to mention is that actually ODR rule is violated very frequently due to subtle changes in the various include header files and miscellaneous defines, but usually there's no problem and people don't even realize this.
For instance a structure may have a member of LPCTSTR type, which is a pointer to either char or wchar_t, depending on the defines, includes and etc. But this type of violation is "almost ok". As long as you don't actually use this member in differently compiled translation units there's no problem.
There're also many other common examples. Some arise from the in-class implemented member functions (inlined), which actually compile into different code within different translation units (due to different compiler options for different translation units for instance).
However this is usually ok. In your case however the memory layout of the structure has changed. And here we have a real problem.
This question already has answers here:
Closed 13 years ago.
Duplicate of the following question: C function conflict
Hi,
in my current project I have to use some kind of interface lib. The function names are given by this interface, what this functions do is developers choice. As far as I can tell a project shall use this functions and when it comes to compiling you choose the lib and with it the functionality. What I try to do is to use an existing lib and my lib at the same time by wrapping the other and call it in mein functions:
otherlib:
int function1 (int a) {
// do something
}
mylib:
int function1 (int a) {
//my code here
otherlib::function1(a);
}
Problem is I don't have access to the other lib and the other lib doesn't have any namespaces. I already tried
namespace old {
#include "otherlib.h"
}
and then call the old function by old::function1 in my function. This works as long as it's only header file. The lib exports it's symbol back into global space. Also something like
namespace new {
function1 (int a) {
::function1(a);
}
}
didn't work. Last but not least I tried ifdefs and defines suggested here
but I wasn't successful.
Any ideas how to solve this? Thanks in advance.
EDIT: I neither have access to the old lib nor the project both libs shall be used in.
EDIT2: at least the old lib is a static one
Namespaces in C solved using library names prefixes like:
libfoo --> foo_function1
libbar --> bar_function1
These prefixes are actual namespaces. so if you write libbar
int bar_function1(int a) {
function1(a);
}
This is the way to solve problems.
C has namespaces --- they just called prefixes ;)
Another option is to do various dirty tricks with dynamic loading of libraries like:
h1=dlopen("libfoo.so")
foo_function1=dlsym(h1,"function1")
h2=dlopen("libbar.so")
bar_function1=dlsym(h2,"function1")
It seems as if the other lib is C and your code is C++. You can be running into a mangling problem (C++ compilers mangle the symbols -- add extra stuff in the symbol name do differentiate overloads and the like).
If the library is pure C you can try:
extern "C" { // disable mangling of symbol names in the block
#include "otherlib.h"
}
namespace new_lib { // new is a reserved word
int function1( int a ) {
::function1(a);
}
}
I have not tried it. Also consider providing the error messages you are getting.
Another option would be (if the library is dynamic) dynamically loading the lib and calling the function. In linux (I don't know about windows) you can use dlopen to open the library, dlsym to obtain the symbol and call it:
// off the top of my head, not tried:
int function1( int a )
{
int (*f)(int); // define the function pointer
void * handle = dlopen( "library.so" );
f = dlsym( handle, "function1" );
f( a ); // calls function1(a) in the dynamic library
}
In this case, as you are not linking against the library you won't get a symbol conflict, but then again, it is only valid for dynamic libraries and it is quite cumbersome for regular usage.
UPDATE
If your users will not use 'otherlib' directly (they won't include their headers) and they will be only C++, then the first approach could be possible (even if horrible to read):
// newlib.h
namespace hideout {
int f( int a );
}
using namespace hideout; // usually I would not put this on the header
// newlib.cpp
extern "C" { // if otherlib is C, else remove this line
#include "otherlib.h"
}
namespace hideout {
int f( int a ) { return ::f( a*2 ); }
}
// main.cpp
#include "newlib.h"
int main()
{
std::cout << f( 5 ) << std::endl;
}
How does it work? User code will only see a declaration of function1 (in the example f()) as they are not including otherlib.h. Inside your compilation unit you see the two declarations but you differentiate through the use of the namespace. The using statement in the header does not bother you as you are fully qualifying in your cpp. The user main.cpp will include only your header, so the compiler will only see hideout::f, and will see it anywhere due to the using statement. The linker will have no problem as the C++ symbol is mangled identifying the real namespace:
// g++ 4.0 in macosx:
00002dbe T __ZN7hideout9function1Ei // namespace hideout, function1 takes int, returns int
00002db0 T _function1
If user code will include both your header and otherlib.h then it will have to qualify which function it wants to call.
If you're really desperate, you could write a wrapper library that uses namespaces or prefixes or allows for the dlsym trick. This wrapper library would need to be dynamically linked (to avoid symbol conflicts). The dynamic library could then safely have the old static library embedded in it. Just make sure you don't export the symbols from the static library when making the dynamic wrapper library.
You can't resolve this at link time, so you'll need to resolve it at runtime via dynamic libraries. The symbol for those functions is essentially baked it once the library has been generated. If two libraries export the same symbol, they cannot both be linked with statically.