Is declaring extern const or just extern the same thing in a header file? Also will both give external linkage?
globals.cpp
#include <string>
extern const std::string foo = "bar";
globals.h
#ifndef GLOBALS_H
#define GLOBALS_H
#include <iostream>
extern const std::string foo;
#endif /* GLOBALS_H */
OR
globals.h
#ifndef GLOBALS_H
#define GLOBALS_H
#include <iostream>
extern std::string foo;
#endif /* GLOBALS_H */
Both compiles and run fine, both give same address when used in multiple files, which one is more correct?
This one is correct,
//globals.h
extern const std::string foo; //Consistent
Consistent!
The correct one is
extern const std::string foo;
foo is a constant string in the source file it is defined in, so the extern declaration should indicate this too and allow the compiler to catch instances where code within source file where that header is included may try to modify foo.
The only reason they both compile fine is that you are not actually using foo, so it doesn't matter whether the linker can find foo or not (it never tries to). (Or your compiler/linker is rubbish. :) )
The consistent header is fine. The one missing the const is not and will/should result in errors if something tries to use foo.
If you make some file (not globals.cpp) which includes globals.h and tries to use foo (e.g. just add a line with "foo.c_str();" into a function) then you'll get a link error because no const std::string foo could be found.
This is how it has to be, too. The header is telling anything that wants to use foo that it can only read it, not modify it. Things which include the globals.h header have no idea of what is inside globals.cpp; if you want them to treat an object as const you have to put that information in a file which they include.
You can give const external linkage, as in your example, but it's still non-modifiable (constant).
P.S. you need to include <string>, not <iostream>
P.P.S. If I wasn't clear, you can't redefine const-ness. This will not compile:
extern std::string foo;
extern const std::string foo = "bar";
For C language, declare actual const in a .c file and use 'extern' for it in a header (.h) file. This should be as usual as we do when declaring a global variable.
Related
I have an header file that i put some global const variables. Now I need another project wide modifiable variable. But it gives linker error as expected. I am trying to solve the issue without using inline keyword. My codes:
constants.h:
#ifndef CONSTANTS_H
#define CONSTANTS_H
namespace constants {
bool myVar;
}
#endif // CONSTANTS_H
I am using this variable in my classes with constants::myVar. And I got a linker error. Any solution without using inline (for backward compiler compability)?
I completely agree with the comments above about looking at alternatives for this design.
Also as you seems to be aware, c++17 inline variables offer a better solution.
Having said that, if you must keep the current design - you can do the following:
Change the header file to declare myVar as extern:
namespace constants {
//--vvvvvv------------
extern bool myVar;
}
Add constants.cpp file (if it doesn't exists yet), with a definition for myVar (preferably with some initialization):
namespace constants {
bool myVar;
// or better: something like:
bool myVar = false;
}
I am declaring and defining a font data in font.h file like this:
#ifndef _DEFAULT_FONT_H
#define _DEFAULT_FONT_H
const unsigned char wwDefaultFont_TextureData[] =
{
0x00,0x01,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,
};
#endif
and I am planing to use this array in render.h file.
So I am including it as #include "font.h"
#include "font.h"
class render{
};
But I am getting link warning LNK4006 error?
What would be the best way to declare this variable and avoid this linking warning?
I think you may not define a header file macro to avoid the header file included repeatedly.
If that's true, you have two ways to avoid this:
Use
#ifndef _FONT_H_
#define _FONT_H_
//font.h content
...
#endif
to make sure it included for only once
If you only use the const variant in font.h,you can use extern to claim it and you need not to include the header file
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why does this not prevent multiple function declarations?
Global.h
#ifndef Global_h
#define Global_h
#include <iostream>
unsigned char exitStatus;
#endif
OutputHandler.h
#ifndef OutputHandler_h
#define OutputHandler_h
#include "Global.h"
class OutputHandler {
private:
static bool instanceExists;
// more code
#endif
Root.h
#ifndef Root_h
#define Root_h
// declarations
OutputHandler *output;
#endif
Root.cpp
#include "Root.h"
// gets instance of OutputHandler
// more code
I am getting errors regarding exitStatus, static bool instanceExists, and static class output being already defined by Root.obj in OutputHandler.obj. I assume the issue is with including the header file OutputHandler.h in both Root.h and OutputHandler.cpp. Anyone know how to fix this or how to better organize header files?
Because include guards only work at the translation unit level (you can, for this simple case, consider a single C file to be a translation unit).
That means a single C file, if it includes the header file twice, will not process it the second time due to the include guards.
However, if you include the header from two different C files, each of them will get a copy of the variables defined in that header.
Then, when you link them together, you get the duplicates.
The easiest way to get around this problem is to never define things in headers, only declare them.
So, in the header (eg, xyzzy.h), you have:
extern int xyzzy; // declare but don't define.
and in all the C files that want to use that, put:
$include "xyzzy.h"
and, in one of those C files, also put:
int xyzzy; // define it here, once.
You can think of declaration as a simple "I declare that this exists somewhere, just not here", while definition is "I an creating this here and now".
Declare extern usigned char exitStatus in Global.h and define it in one implementation file.
The problem is during the linking phase; include guards in the headers won't help you.
In C, there is the separate concepts of declarations and definitions. Declarations are what are put into headers; they merely state that a particular variable exists. The definition of a variable is where storage is actually allocated for it.
For example, in your Global.h, you have:
#ifndef Global_h
#define Global_h
#include <iostream>
usigned char exitStatus;
#endif
This is defining a variable called exitStatus, and the linker is complaining because any given variable should only be defined in one place in a program. What you need to do is declare it in the header, and then define it in only one place in a source (*.cpp) file. For example, your header should declare exitStatus with:
extern char exitStatus;
and in only one source file, define it with:
char exitStatus;
The situation is similar for output in Root.h, as well as any other place you should be declaring variables in the header file.
See also: http://www.cprogramming.com/declare_vs_define.html
Api.cpp:
int (*theFunc) (int);
theFunc = (int (*) (int)) DlSym(hSo, "theFunc");
So far so good.
Now, I want to make a header so that other cpp files can also call theFunc.
Api.h: per How to declare function pointer in header and c-file?
extern int (*theFunc)(int);
/usr/bin/ld: Warning: type of symbol `theFunc' changed from 2 to 1 in Api.o
OK, so this is a warning that theFunc is seen as a function from one compilation element and as a variable in another. (Reference) This seems like bad things will happen at runtime.
This seems to be a proper declaration, what am I doing wrong?
Edit: Actually running in linux, so use DlSym not Microsoft GetProcAddress() call
According to the linked post, condense it to one line, not two in the .cpp file. So the .h seems right, and put this in the .cpp file:
int (*theFunc) (int) = (int (*) (int)) GetProcAddress(hDll, "theFunc");
You're not doing declaration and assignment in one shot like the linked answer is. With what I posted above, you will be.
You probably should not include Api.h
Alternatively you may work with macros in a way that api.h behave somewhat different when included by api.cpp.
MicroSoft has done/do such things.
api.h
#ifdef _API_
#define EXTERN
#else
#define EXTERN extern
#endif
EXTERN int (*theFunc)(int);
api.cpp
#define _API_
#include "api.h"
...
other.cpp
#define _OTHER_
#include "api.h"
...
I have 4 files:
shared.h
main.cpp
something.h
something.cpp
shared.h:
#ifndef SHARED_H
#define SHARED_H
int* sth;
#endif
something.h:
#ifndef SOMETHING_H
#define SOMETHING_H
class foo
{
public:
void printVar();
};
#endif
something.cpp:
#include <iostream>
#include "something.h"
#include "shared.h"
using namespace std;
void foo::printVar()
{
cout<<"Foo: "<<*sth<<endl;
};
main.cpp:
#include <cstdlib>
#include <iostream>
#include "shared.h"
#include "something.h"
using namespace std;
int main(int argc, char *argv[])
{
sth=new int(32);
foo x;
cout<<"Main: "<<*sth<<endl;
x.printVar();
system("PAUSE");
return EXIT_SUCCESS;
}
Compiler returns multipe definition of *sth;
I added static modifier to the *sth and it compiles, but crashes. I changed the printings to print the adresses of pointer and I had program returned:
Main: 0x3e0f20
Foo: 0
Why is the foo's pointer not assigned? I want to assign it only once in main and then share in other files... How can I do this? Is it something with extern modifier?
Thanx for any replies.
In shared.h you want to say:
extern int* sth;
to promise the compiler that sth exists somewhere.
Then in one (and only one) of the .cpp files you need to write:
int* sth;
To make it actually exists. In general you probably want to read about the difference between declaration and definition. As a rule of thumb you only want to declare things in header files, not define them.
When you wrote static previously you said that a variable with the same name exists in every file, but is "local" to each, i.e. the sth in main.cpp won't be the same as the sth in something.cpp.
Yes, use extern. Put extern int* sth; in the header, and then in one of the source files put int* sth;.
extern tells the compiler and linker that the actual variable/function definition is in another compilation unit (i.e. another source file).
You need to mark sth as extern in the header to make it a declaration, and provide a definition for it in one of the cpp files. Otherwise, the variable is declared in each compilation unit where the header is included, which is not the effect you are looking for.
P.S. I assume that you know why global variables are not good, right?
"I have 4 files".
Let me stop you right there. I agree that you have four files, but that's not really relevant. You have two translation units. A translation unit is the quantum of text that is fed into your compiler. Your translation units, let's call them MAIN and SOMETHING, consist of the result of preprocessing your files main.cpp and something.cpp, respectively.
After preprocessing, each of your translation units includes a line int *sth; This line declares and defines the variable sth.
The one-definition-rule requires that you have, in your entire program, exactly one (not more, not fewer) definition of sth. In order to accomplish this, you must have exactly one source-code line int *sth; in exactly one translation unit, and as many extern int *sth; as you require.
In your case, I would put int *sth; in MAIN and extern int *sth; in SOMETHING. Additionally, you can have as many extra copies of extern int *sth; as you feel like -- they won't hurt anything.
Now, back to your four files. You should put extern int *sth; in shared.h. This means that MAIN and SOMETHING will both have an extern line in them. You should also put int *sth; in main.cpp, so that MAIN will have the definition.
And there you are: MAIN and SOMETHING both have extern lines, so they are both referring to the same variable. MAIN also has a definition. so the sth variable has exactly one of those.
Aside: Why does static int *sth; in shared.h do the wrong thing?
Because each of the two translation units see their own static declaration. A static declaration reduces the linkage of the declared name to that single translation unit.
You don't want to make it a static global as that will create a local sth in every translation unit and you are only allocating it in one. This is why it crashed in Foo::printVar as in that scope it was an uninitialized pointer.
You want to declare it as extern int* sth; in the shared header then put int* sth; before main or in at least one place before it's used.
Actually, if you really need a globally accessible object, allocated on the heap, and you want to share it then it may be better as extern std::shared_ptr<int> sth;. Define it as std::shared_ptr<int> sth; the same way in one of the CPP files and call std::make_shared to allocate it. This way deallocating the memory will be handled automatically when the last object that uses it goes out of scope.