I need to use a static fstream in multiple source files. However I can only use it from a single file and not from the others. Furthermore, its use in the other files does not give any error, it just does nothing.
This is the code:
/// log.h
#ifndef LOG_H
#define LOG_H
#include <fstream>
static std::ofstream ofs;
#define LOG(level) ofs << level << ": "
#endif
/// test.cpp
#include "log.h"
#include "other.h"
int main()
{
ofs.open("file.log");
LOG(5) << "Test log 1" << std::endl; // OK
OtherFunc();
}
/// other.h
#ifndef OTHER_H
#define OTHER_H
extern int OtherFunc();
#endif
/// other.cpp
#include "other.h"
#include "log.h"
int OtherFunc()
{
LOG(5) << "Test log 2" << std::endl; // Nothing
}
This is the generated file:
5: Test log 1
Thank you!
Platform:
Linux
g++ 4.5.1
Static global variables: variables declared as static at the top level of a source file (outside any function definitions) are only visible throughout that file ("file scope", also known as "internal linkage").
The default storage class for global variable is extern which has external or whole program linkage. So if you want to use the global variable in multiple files it must be extern.
static here means you're explicitly asking the compiler to give the file-scope variable std::ofstream ofs static linkage, which means it is visibly only in the current file.
The twist is that you're doing this in a header, which means every .cpp file including the header gets its own distinct instance of std::ofstream ofs. Only because you've given it static linkage can they all have distinct file-scope variables with the same name - otherwise there would be a name clash.
So, in main.cpp, you open your local ofs and write to it.
In other.cpp, you have your own local copy of ofs, but never open it ... so the output doesn't go anywhere, and certainly not to file.log.
The other answers are correct, that changing the header declaration to extern std::ofstream ofs; will allow all the .cpp files to share a single object called ofs, and then you just need to put the instance in exactly one place (main.cpp would be fine).
It might be simpler, and cleaner, to make the LOG(level) an out-of-line function call though; then the output stream could live in a log.cpp with the function definition, and nobody else needs to see it.
I need to use a static fstream in multiple source files.
If you need to reference the same variable from multiple source files, that isn't static linkage, that is extern linkage.
Put this in your header:
extern std::ofstream ofs;
Put this in exactly one of your CPP files:
std::ofstream ofs;
Related
I want to run a small simulation in c++.
To keep everything nice and readable I seperate each thing (like all the sdl stuff, all the main sim stuff, ...) into it's own .h file.
I have some variables that I want all files to know, but when I #include them in more then one file other the g++ compliler sees it as a redefinition.
I understand why he does this, but this still leaves me with my wish to have one file where all important variables and constants for each run are defined and known to all other files, to easily find and change them when running my simulation.
So my Question here: Is there a good workaround to achieve that or something similar?
You can put the declarations for all the globals in a header and then define them in a source file and then you will be able to use those global variables in any other source file by just including the header as shown below:
header.h
#ifndef MYHEADER_H
#define MYHEADER_H
//declaration for all the global variables
extern int i;
extern double p;
#endif
source.cpp
#include "header.h"
//definitions for all the globals declared inside header.h
int i = 0;
double p = 34;
main.cpp
#include <iostream>
#include "header.h" //include the header to use globals
int main()
{
std::cout << i <<std::endl;//prints 0
std::cout<< p << std::endl;//prints 34
return 0;
}
Working demo
Mark them as extern in the header and have one translation unit that defines them.
Note: Without LTO (link time optimization) this will seriously slow down your simulation.
I have 2 header files and 1 source file to work with. Respectively: Utility.h, Game.h and main.cpp. I have declared extern variables in Utility.h and am trying to define them in main.cpp. This gives me an undefined reference error, which I don't understand. I use the variable AFTER I give it a value, so that should be fine?
Utility.h:
#pragma once
#include <string>
#include <fstream>
#include <SDL.h>
namespace Utility {
extern std::string BIN_PATH;
extern std::string ROOT_PATH;
extern std::string EXE_PATH;
// Omitted rest of namespace.
}
main.cpp
#include "Game.h"
int main(int argc, char * argv[]) {
// Get the necessary paths
std::string path = SDL_GetBasePath();
#ifdef _WIN32
// TODO check if working on different windows systems
// exePath = path;
// binPath = path.substr(0, path.find_last_of('\\'));
// rootPath = binPath.substr(0, binPath.find_last_of('\\'));
#elif __LINUX__
Utility::BIN_PATH = path.substr(0, path.find_last_of('/'));
Utility::ROOT_PATH = Utility::BIN_PATH.substr(0, binPath.find_last_of('/'));
// TODO check if working on different linux systems
#endif
std::cout << "BinPath: " + Utility::BIN_PATH << std::endl;
std::cout << "RootPath: " + Utility::ROOT_PATH << std::endl;
// Omitted rest of source.
}
I am including Utility.h in Game.h, and Game.h in main.cpp. Shouldn't that put the extern definitions above my main.cpp source when linking?
To simplify (rather complicated) rules a bit, each variable (as well as other entities) must be defined once and only once in the whole program. It can be declared multiple times. It is important to understand what is a declaration and what is a definition.
extern std::string var; // in namespace scope
Is a declaration of string variable var. var is not yet defined. You need to define it somewhere else - only once - by using
std::string var; // in namespace scope!
In your code, you do not define the variable in function main - instead, you are assigning the value to it. But the variable needs to be defined.
The lines
Utility::BIN_PATH = path.substr(0, path.find_last_of('/'));
Utility::ROOT_PATH = Utility::BIN_PATH.substr(0, binPath.find_last_of('/'));
don't define the variables. They just assign values to them. To define them, use:
std::string Utility::BIN_PATH;
std::string Utility::ROOT_PATH;
in the global scope. Add similar line for EXE_PATH.
std::string Utility::EXE_PATH;
You can also define them using
namespace Utility
{
std::string BIN_PATH;
std::string ROOT_PATH;
std::string EXE_PATH;
}
Make sure that those lines appear in a .cpp file, not in a .h file.
When I declared and initialized a const object.
// ConstClass.h
class ConstClass
{
};
const ConstClass g_Const;
And two cpp files include this header.
// Unit1.cpp
#include "ConstClass.h"
#include "stdio.h"
void PrintInUnit1( )
{
printf( "g_Const in Unit1 is %d.\r\n", &g_Const );
}
and
// Unit2.cpp
#include "ConstClass.h"
#include "stdio.h"
void PrintInUnit2( )
{
printf( "g_Const in Unit2 is %d.\r\n", &g_Const );
}
When i build the solution, there was no link error, what you will get If g_Const is a non-const fundamental type!
And PrintInUnit1() and PrintInUnit2() show that there are two independent "g_Const"s with different address in two compilation units, Why?
==============
I know how to fix it.(use extern keyword to declaration, and define it in one cpp file.)
I wonder to know why I did't get redfined link error in this sample.
https://stackoverflow.com/a/6173889/1508519
const variable at namespace scope has internal linkage. So they're
basically two different variables. There is no redefinition.
3.5/3 [basic.link]:
A name having namespace scope (3.3.5) has internal linkage if it is
the name of
— an object, reference, function or function template that is
explicitly declared static or,
— an object or reference that is explicitly declared const and neither
explicitly declared extern nor previously declared to have external
linkage; or
— a data member of an anonymous union.
Use extern if you want it to have external linkage.
As stated in the other answer, header files are just pasted in cpp files. The same header file is included in both cpp files, but they are separate translation units. That means that one instance of a variable is different from the other instance. In other to let the compiler know that you have defined the variable elsewhere, use the extern keyword. This ensures only one instance is shared across translation units. However extern const Test test is just a declaration. You need a definition. It doesn't matter where you define it as long as it is defined once in some cpp file. You can declare it as many times as you want (which is convenient for placing it in a header file.)
So for example:
Constant.h
class Test
{
};
extern const Test test;
Unit1.cpp
#include "Constant.h"
#include <iostream>
void print_one()
{ std::cout << &test << std::endl; }
Unit2.cpp
#include "Constant.h"
#include <iostream>
void print_two()
{ std::cout << &test << std::endl; }
main.cpp
extern void print_one();
extern void print_two();
int main()
{
print_one();
print_two();
}
Constant.cpp
#include "Constant.h"
const Test test = Test();
Makefile
.PHONY: all
all:
g++ -std=c++11 -o test Constant.cpp Unit1.cpp Unit2.cpp main.cpp
Because you put variable definition in header file. Including header file is just like replacing it with the content of the file. So, the first file:
// Unit1.cpp
#include "ConstClass.h" // this will be replace with the content of ConstClass.h
#include "stdio.h"
void PrintInUnit1( )
{
printf( "g_Const in Unit1 is %d.\r\n", &g_Const );
}
will become (after preprocessing phase before compiling):
// Unit1.cpp
// ConstClass.h
class ConstClass
{
};
const ConstClass g_Const;
//this line is replaced with the content of "stdio.h"
void PrintInUnit1( )
{
printf( "g_Const in Unit1 is %d.\r\n", &g_Const );
}
And the second file will be:
// Unit2.cpp
// ConstClass.h
class ConstClass
{
};
const ConstClass g_Const;
//this line is replaced with the content of "stdio.h"
void PrintInUnit2( )
{
printf( "g_Const in Unit2 is %d.\r\n", &g_Const );
}
As you can see, each file has separate variable g_Const (this is just for the case of your code in here, there maybe no variable at all just like macro, see explanation in my last paragraph).
If what you want is not the definition of the variable just the declaration in the header file, you should use extern keyword in the header file:
extern const ConstClass g_Const;
Then you can put the definition of g_Const variable in ConstClass.c
There is some catch in your code:
there is no constant value assigned in your g_Const definition, you must assign it a constant value in the definition unless you want the default value (0).
inside printf, you take the address of const variable of C++. This actually force the compiler to create the variable in stack. If you don't take the address it may be able to infer a compile time number behaving like macro in C (you can get the magic number directly put in the code where you use the const variable).
I am playing around with multiple files in C++, and I have come of with the following example with does not compile:
main.cpp
#include <iostream>
#include "const.hpp"
using namespace std;
int main()
{
extern double var;
var = 5;
cout << var << endl;
return 0;
}
fct.cpp
#include <iostream>
#include "const.hpp"
using namespace std;
void func()
{
extern double var;
cout << var << endl;
}
const.hpp
#ifndef CONST_H
#define CONST_H
double var;
#endif
My program does not compile, because apparently there is a multi-definition of var. Am I correct to assume that, based on this example, a header file is not intended to be used for declaring variables as in my example above?
Instead, the correct procedure is to declare all variables in a .cpp file and use a header to tell each (relevant) translation unit that the .cpp file contains an external (extern) variable?
EDIT: Is it correct that an exeption to my rule above is when dealing with constant variables (const), which should be defined in a header?
double var; is a definition - including that header in multiple files will violate the one definition rule. If you want a global (think twice) you'll have to declare it in the header - extern double var; and move the definition to a single implementation file.
Am I correct to assume that, based on this example, a header file is not intended to be used for declaring variables as in my example above?
A header file is intended for declaring variables, but your header file defines a global variable with external linkage, and it is imported multiple times. The linker then reasonably complains about multiply defined symbols.
Instead, the correct procedure is to declare all variables in a .cpp file and use a header to tell each (relevant) translation unit that the .cpp file contains an external (extern) variable?
Yes, except that you would not be declaring the global variables in that .cpp file, but rather providing a definition for them.
const.hpp
#ifndef CONST_H
#define CONST_H
// ...
extern double var;
// ^^^^^^
#endif
globals.cpp (could be any other .cpp file, as long as it is only one)
// ...
double var;
Also, if you are wondering about the reason why your include guards won't protect you in this case, this may help you .
Is it correct that an exception to my rule above is when dealing with constant variables (const), which should be defined in a header?
In a sense, yes. Global variables qualified as const have internal linkage by default, which means that each translation unit will receive a private copy of that variable. So even when the variable's definition is included by multiple translation unit, the linker will not complain about multiply defined symbols.
I'm trying to do this:
#pragma once
#include <fstream>
#include <string>
static std::ofstream ErrorLog;
void InitErrorLog(std::string FileName) {
ErrorLog.open(FileName);
}
but am getting a "One or more multiply defined symbols found" error when #include-ing in multiple CPP files. What is the STL doing (to provide cout, cin, cerr, etc. -- this approach originates as an alternative to redirecting cerr) that I'm not?
You are providing the definition for ErrorLog in a header file. Instead, define it in a source file and leave an extern declaration at the header.
source
std::ofstream ErrorLog;
void InitErrorLog(std::string FileName) {
ErrorLog.open(FileName);
}
header
extern std::ofstream ErrorLog;
void InitErrorLog(std::string FileName);
Additionaly, in order to keep your function at the header you have to make it inline.
You're breaking the one definition rule. You need to make the method inline.
inline void InitErrorLog(std::string FileName) {
ErrorLog.open(FileName);
}
Also, note that by declaring your variable static, you'll have a copy per translation unit - i.e. it's not a global. To make it global, you need to declare it extern in the header and define it in a single implementation file.