I was playing a bit with external variables and was wondering why I cannot access an external structure from outside functions?
Here's my code:
a.h
struct testing {
unsigned int val;
const char* str;
testing(unsigned int aVal, const char* aStr) : val(aVal), str(aStr){};
}
extern testing externalStruct;
a.c
#include "a.h"
testing externalStruct(10, "test");
test.c
#include <iostream>
#include "a.h"
unsigned int valCopy = externalStruct.val;
const char* strCopy = externalStruct.str;
int main()
{
std::cout<<"Direct val : "<<externalStruct.val<<std::endl; // Working, print 10
std::cout<<"Direct str : "<<externalStruct.str<<std::endl; // Working, print "test"
std::cout<<"Copy val : "<<valCopy<<std::endl; // Print 0 instead of 10
std::cout<<"Copy str : "<<strCopy<<std::endl; // Print nothing
return 0;
}
Any idea?
This problem is caused by the fact that order of initialization of static (global) variables is unknown. It even has a name static initialization order fiasco. This means that global variables from test.c translation unit were initialized before global variables from a.c transation unit.
The usual solution is to use function with static variable. When function is called then static variable (during first use) is initialized. With c++11 initialization of such static function local variables is thread safe.
Solution for your code could look as follows:
a.h
//...
testing& GetExternalStruct();
a.c
//...
testing& GetExternalStruct() {
static testing externalStruct(10, "test");
return externalStruct;
}
test.c
unsigned int valCopy = GetExternalStruct().val;
const char* strCopy = GetExternalStruct().str;
You are being tricked by the static initialization order fiasco - One of the shortcomings of C++.
Both
unsigned int valCopy = externalStruct.val;
const char* strCopy = externalStruct.str;
and
testing externalStruct(10, "test");
are (and need to be) actually called before main() is executed. Unfortunately, C++ has no language construct that allows you to express in what order the initialization should be done - this is more ore less randomly decided by the compiler - In your case, the first block is apparently executed before the second, leading to the fact that externalStruct has not been initialized yet when you copy values from there into valCopy and strCopy.
You can work around this language deficiency by wrapping the initializations into functions that return a statically initialized value - This gives you control over the order those initializations are done.
a.c:
testing &x() {
static testing *t = new testing(10, "test");
return *t;
}
test.c
...
valCopy = x().val;
strCopy = x().str;
...
The order of initialization of the global objects is not defined.
In this case I guess that valCopy and strCopy were initialized before the constructor of externalStruct was invoked (=> initialized with junk).
If you put the initialization of valCopy and strCopy into the main body I believe everything will work properly:
int main()
{
unsigned int valCopy = externalStruct.val;
const char* strCopy = externalStruct.str;
std::cout<<"Direct val : "<<externalStruct.val<<std::endl; // Working, print 10
std::cout<<"Direct str : "<<externalStruct.str<<std::endl; // Working, print "test"
std::cout<<"Copy val : "<<valCopy<<std::endl; // ??? did it work?
std::cout<<"Copy str : "<<strCopy<<std::endl; // ??? did it work?
return 0;
}
EDIT
More info is here "C++ global initialization order ignores dependencies?"
Related
Everything works in Visual Studio 2017, but I get linker errors in GCC (6.5.0).
Here is some sample code that isolates my problem:
#include <iostream>
struct Foo{
static constexpr const char* s[] = {"one","two","three"};
};
int main(){
std::cout << Foo::s[0] << std::endl; //this works in both compilers
const char* const* str_ptr = nullptr;
str_ptr = Foo::s; //LINKER ERROR in GCC; works in VS
std::cout << str_ptr[1] << std::endl; //works in VS
return 0;
}
In GCC, I get undefined reference to 'Foo::s'. I need the initialization of Foo::s to stay in the declaration of the struct, which is why I used constexpr. Is there a way to reference Foo::s dynamically, i.e. with a pointer?
More Background Info
I'll now explain why I want to do this. I am developing embedded software to control configuration of a device. The software loads config files that contain the name of a parameter and its value. The set of parameters being configured is determined at compile-time, but needs to be modular so that it's easy to add new parameters and expand them as development of the device continues. In other words, their definition needs to be in one single place in the code base.
My actual code base is thousands of lines and works in Visual Studio, but here is a boiled-down toy example:
#include <iostream>
#include <string>
#include <vector>
//A struct for an arbitrary parameter
struct Parameter {
std::string paramName;
int max_value;
int value;
const char* const* str_ptr = nullptr;
};
//Structure of parameters - MUST BE DEFINED IN ONE PLACE
struct Param_FavoriteIceCream {
static constexpr const char* n = "FavoriteIceCream";
enum { vanilla, chocolate, strawberry, NUM_MAX };
static constexpr const char* s[] = { "vanilla","chocolate","strawberry" };
};
struct Param_FavoriteFruit {
static constexpr const char* n = "FavoriteFruit";
enum { apple, banana, grape, mango, peach, NUM_MAX };
static constexpr const char* s[] = { "apple","banana","grape","mango","peach" };
};
int main() {
//Set of parameters - determined at compile-time
std::vector<Parameter> params;
params.resize(2);
//Configure these parameters objects - determined at compile-time
params[0].paramName = Param_FavoriteIceCream::n;
params[0].max_value = Param_FavoriteIceCream::NUM_MAX;
params[0].str_ptr = Param_FavoriteIceCream::s; //!!!! LINKER ERROR IN GCC !!!!!!
params[1].paramName = Param_FavoriteFruit::n;
params[1].max_value = Param_FavoriteFruit::NUM_MAX;
params[1].str_ptr = Param_FavoriteFruit::s; //!!!! LINKER ERROR IN GCC !!!!!!
//Set values by parsing files - determined at run-time
std::string param_string = "FavoriteFruit"; //this would be loaded from a file
std::string param_value = "grape"; //this would be loaded from a file
for (size_t i = 0; i < params.size(); i++) {
for (size_t j = 0; j < params[i].max_value; j++) {
if (params[i].paramName == param_string
&& params[i].str_ptr[j] == param_value) {
params[i].value = j;
break;
}
}
}
return 0;
}
As you can see, there are enums and string arrays involved and these need to match, so for maintenance purposes I need to keep these in the same place. Furthermore, since this code is already written and will be used in both Windows and Linux environments, the smaller the fix, the better. I would prefer not to have to re-write thousands of lines just to get it to compile in Linux. Thanks!
The program is valid in C++17. The program is not valid in C++14 or older standards. The default standard mode of GCC 6.5.0 is C++14.
To make the program conform to C++14, you must define the static member (in exactly one translation unit). Since C++17, the constexpr declaration is implicitly an inline variable definition and thus no separate definition is required.
Solution 1: Upgrade your compiler and use C++17 standard (or later if you're from the future), which has inline variables. Inline variables have been implemented since GCC 7.
Solution 2: Define the variable outside the class definition in exactly one translation unit (the initialisation remains in the declaration).
It looks like you are not using C++17, and pre-C++17 this is undefined behavior, and one that I really dislike. You do not have a definition for your s, but you are ODR-using it, which means that you need to have a definition.
To define this, you have to define it in .cpp file.
In C++17 that would be the valid code. I am not familiar with MSVC, so I am not sure why it works fine there - be it that it is compiled as C++17, or because it is just a different manifestation of undefined behavior.
For C++98, C++11, and C++14 you need to explicitly tell the compiler where the initialization of Foo::s lives (see below) and you are good to go.
struct Foo{
static const char* s[];
};
const char* Foo::s[] = {"one","two","three"};
And as explained in one of the comments your initialization is OK from C++17.
I have a static unordered_map in my class C. I experience difference in behaviour if I put my class definition and declaration in different files from the file containing function main.
The thing is that I observed that if the class C is in the same compilation unit as function main, all is well, I see only once the text "new string created: c". However if I split my code into three files (see the listing below), I see "new string created: c" twice which means that my static unordered_map is wiped right before entering main.
My question would be: why does this happen? (The difference only happens when compiling with Apple LLVM compiler 4.1. I have tested it with g++4.7 -std=c++11 and the split code works out just fine.)
Thanks in advance for any ideas!
// would go to My_header.h
#include <unordered_map>
#include <string>
#include <iostream>
using namespace std;
class C{
public:
C(const string & s);
private:
static unordered_map<string, string*> m;
string *name;
};
// would go to My_code.cpp
// (when separated, add #include "My_header.h")
unordered_map<string, string*> C::m;
C::C(const string & s):
name(NULL)
{
string*& rs = m[s];
if(rs)
{
name = rs;
}
else
{
cout<<"new string created: "<<s<<endl;
rs = name = new string(s);
}
}
// would go to main.cpp
// (when separated, add #include "My_header.h")
C c("c");
int main(int argc, const char * argv[])
{
cout << "main" << endl;
C c1("c");
}
The order of initialization of global objects is defined only within one translation unit. Between different translation the order isn't guaranteed. Thus, you probably see behavior resulting from the std::unordered_map being accessed before it is constructed.
The way to avoid these problems is to not use global objects, of course. If you realky need to use a global object it is best to wrap the object by a function. This way it is guaranteed that the object is constructed the first time it is accessed. With C++ 2011 the construction is even thread-safe:
T& global() {
static T rc;
return rc;
}
Thanks, guys! Following Dietmar's advice, I did this:
class C{
//...
private:
static unordered_map<string, string*>& m();
};
unordered_map<string, string*>& C::m()
{
static unordered_map<string, string*> m;
return m;
}
and then I kept referring to m(). It is strange that it did not happen before. I guess I got lucky. But then, this should be a case for a warning message, shouldn't it?
To avoid mistakes like this I will use the following macros to declare and define static variables:
/// Use this macro in classes to declare static variables
#define DECLARE_STATIC(type, name) static type& name();
/// Use this macro in definition files to define static variables
#define DEFINE_STATIC(type, name) type& name(){static type local; return local;}
Usage in this case:
class C{
//...
private:
DECLARE_STATIC(unordered_map<string, string*>, m);
}
DEFINE_STATIC(unordered_map<string, string*>, m)
I have a classcalled Tracer in C++. In my Tracer.h file I have:
class Tracer{
public:
// not useful to the question.
private:
Logger *m_logger;
const char *m_who;
const char *m_fileName;
const void * m_theObject;
int m_lineNum;
int m_log_level;
}
And in Tracer.cpp I have:
Tracer::Tracer(
Logger *logger,
const void *theObject,
const char *who,
const char *file,
int line,
int log_level
) :
m_logger(logger),
m_who(who),
m_fileName(file),
m_lineNum(line),
m_theObject(theObject),
m_log_level(log_level)
{
// more implementation which is not useful to the problem.
The problem is, when I initialize m_theObject(theObject), I get the following warning:
/home/pribeiro/workspace/Tracer.h:80: warning: 'const void* Tracer::m_theObject'
/home/pribeiro/workspace/Tracer.cpp:27: warning: when initialized here
Tracer.h:80 is the declaration of m_theObject in the Tracer.h and Tracer.cpp:27 is the m_theObject(theObject line.
In my compilation level, warnings are treated like errors. Why is the compiler complaining about the initiliazation of a const void * pointer?
That's not the whole warning. It's actually warning that m_lineNum and m_theObject are being initialised in the wrong order (see Member fields, order of construction):
Tracer.h:80: warning: 'const void* Tracer::m_theObject' is initialized before 'int Tracer::m_lineNum'
Tracer.cpp:27: warning: when initialized here
The fix is to swap the order of initialisation, or the order of definition:
Tracer::Tracer(
Logger *logger,
const void *theObject,
const char *who,
const char *file,
int line,
int log_level
) :
m_logger(logger),
m_who(who),
m_fileName(file),
m_theObject(theObject), // here
m_lineNum(line), // and here
m_log_level(log_level)
{
// more implementation which is not useful to the problem.
Sometimes compilers give a warning when members are initialised in the member initialisation list in a different order than they are declared in the header. I have seen g++ do this before. If you reorder your initialisation list so that it is in the same order as the members appear in your header file you should see this warning disappear.
The issue here is that, as per the C++ Standard, member variables are always (ALWAYS) initialized in the order of declaration, regardless of the order you give in the constructor.
The compiler nicely warns you about your misfit, because possibly you introduce unintended dependency chains.
Example:
struct Foo {
int _1, _2, _3;
Foo() : _3(_2+_1), // Third initialization
_2(_1+_1), // Second initialization
_1(1) // First initialization
{}
};
#include <iostream>
int main () {
Foo f;
std::cout << f._1 << f._2 << f._3 << '\n';
}
Output:
123
But the order of member initializers may let the maintainer think he could do better:
struct Foo {
int _1, _2, _3;
Foo() : _3(3),
_2(_3-1),
_1(_2-1)
{}
};
#include <iostream>
int main () {
Foo f;
std::cout << f._1 << f._2 << f._3 << '\n';
}
One might again expect the output of 123 as it looks like _3 is initiliazed first in that constructor. But that's not true:
./teh_program
13451434436167553
./teh_program
134514344118742913
./teh_program
13451434495068033
The results are totally unpredictable, multiple runs give different results without even recompiling. And the compiler is to prevent accidents like this.
I'm considering a certain solution where I would like to initialize a cell of an array that is defined in other module (there will be many modules initializing one table). The array won't be read before running main (so there is not problem with static initialization order).
My approach:
/* secondary module */
extern int i[10]; // the array
const struct Initialize {
Initialize() { i[0] = 12345; }
} init;
/* main module */
#include <stdio.h>
int i[10];
int main()
{
printf("%d\n", i[0]); // check if the value is initialized
}
Compiler won't strip out init constant because constructor has side effects. Am I right? Is the mechanism OK? On GCC (-O3) everything is fine.
//EDIT
In a real world there will be many modules. I want to avoid an extra module, a central place that will gathered all minor initialization routines (for better scalability). So this is important that each module triggers its own initialization.
This works with MSVC compilers but with GNU C++ does not (at least for me). GNU linker will strip all the symbol not used outside your compilation unit. I know only one way to guarantee such initialization - "init once" idiom. For examle:
init_once.h:
template <typename T>
class InitOnce
{
T *instance;
static unsigned refs;
public:
InitOnce() {
if (!refs++) {
instance = new T();
}
}
~InitOnce() {
if (!--refs) {
delete instance;
}
}
};
template <typename T> unsigned InitOnce<T>::refs(0);
unit.h:
#include "init_once.h"
class Init : public InitOnce<Init>
{
public:
Init();
~Init();
};
static Init module_init_;
secondary.cpp:
#include "unit.h"
extern int i[10]; // the array
Init::Init()
{
i[0] = 12345;
}
...
I don't think you want the extern int i[10]; in your main module, though, adf88.
EDIT
/*secondary module (secondary.cpp) */
int i[10];
void func()
{
i[0]=1;
}
.
/*main module (main.cpp)*/
#include<iostream>
extern int i[];
void func();
int main()
{
func();
std::cout<<i[0]; //prints 1
}
Compile, link and create and executable using g++ secondary.cpp main.cpp -o myfile
In general constructors are used(and should be used) for initializing members of a class only.
This might work, but it's dangerous. Globals/statics construction order within a single module is undefined, and so is module loading order (unless you're managing it explicitly). For example, you assume that during secondary.c Initialize() ctor run, i is already present. You'd have to be very careful not to have two modules initialize the same common data, or have two modules carry out initializations with overlapping side effects.
I think a cleaner design to tackle such a need is to have the owner of the common data (your main module) expose it as a global singleton, with an interface to carry out whichever data initializations needed. You'd have a central place to control init-order, and maybe even control concurrent access (using critical sections or other concurrency primitives). Along the lines of your simplified example, that might be -
/main module (main.c)/
#include
class CommonDat
{
int i;
public:
const int GetI() { return i;}
void SetI(int newI) { i = newI; }
void incI()
{
AcquireSomeLock();
i++;
ReleaseTheLock();
}
}
CommonDat g_CommonDat;
CommonDat* getCommonDat() { return &g_CommonDat; }
int main(void)
{
printf("%d",getCommonDat()->GetI());
}
It's also preferable to have the secondary modules call these interfaces at controlled times in runtime (and not during the global c'tors pass).
(NOTE: you named the files as C files, but tagged the question as c++. The suggested code is c++, of course).
May I ask why you use an array (running the risk of getting out of bounds) when you could use a std::vector ?
std::vector<int>& globalArray()
{
static std::vector<int> V;
return V;
}
bool const push_back(std::vector<int>& vec, int v)
{
vec.push_back(v);
return true; // dummy return for static init
}
This array is lazily initialized on the first call to the function.
You can use it like such:
// module1.cpp
static bool const dummy = push_back(globalArray(), 1);
// module2.cpp
static bool const dummy = push_back(globalArray(), 2);
It seems much easier and less error-prone. It's not multithread compliant until C++0x though.
In C++ I wanted to define a constant that I can use in another function, A short answer on how to do this will be fine..
Lets say at the beginning of my code I want to define this constant:
//After #includes
bool OS = 1; //1 = linux
if (OS) {
const ??? = "clear";
} else {
const ??? = "cls";
}
I don't know what type to use to define the "clear" string... I'm so confused.
Later on I want to use it within a function:
int foo() {
system(::cls); //:: for global
return 0;
}
How would I define the string up top, and use the string down below? I heard char only had one character and things... I'm not sure how to use , since it says it's converting string into const char or something.
char* isn't quite a char. char* is basically a string (it's what strings were before C++ came along).
For illustration:
int array[N]; // An array of N ints.
char str[N]; // An array of N chars, which is also (loosely) called a string.
char[] degrades to char*, so you'll often see functions take a char*.
To convert std::string to const char*, you can simply call:
std::string s;
s.c_str()
In this case, it's common to use the preprocessor to define your OS. This way you can use the compiler to do the platform specific stuff:
#ifdef OS_LINUX
const char cls[] = "clear";
#elif OS_WIN
const char cls[] = "cls";
#endif
One thing you may want to consider is making it a function. This avoids nasty dependencies of global construction order.
string GetClearCommand() {
if (OS == "LINUX") {
return "clear";
} else if (OS == "WIN") {
return "cls";
}
FAIL("No OS specified?");
return "";
}
What it looks like you're trying to do is this:
#include <iostream>
using namespace std;
#ifdef LINUX
const char cls[] = "LINUX_CLEAR";
#elif WIN
const char cls[] = "WIN_CLEAR";
#else
const char cls[] = "OTHER_CLEAR";
#endif
void fake_system(const char* arg) {
std::cout << "fake_system: " << arg << std::endl;
}
int main(int argc, char** argv) {
fake_system(cls);
return 0;
}
// Then build the program passing your OS parameter.
$ g++ -DLINUX clear.cc -o clear
$ ./clear
fake_system: LINUX_CLEAR
Here's the problem, you're suffering from going out of scope with the variables. If I declare something within brackets, it only exists within the brackets.
if( foo ){
const char* blah = "blah";
}
Once we leave the if statement, the variable blah disappears. You'll need to instantiate it non-locally to whatever brackets you write. Hence:
void Bar(){
const char* blah = "blah";
if( foo ){
//blah exists within here
}
}
However, blah will not exist outside of Bar. Get it?
Yet another option is to create a class with a bunch of static methods. Create a new method for each command. Something like:
// in sys-commands.h
class SystemCommands {
public:
static char const* clear();
static char const* remove();
};
This gives you a few nice options for the implementation. The nicest one is to have a separate implementation file for each platform that you select during compile time.
// in sys-commands-win32.cpp
#include "sys-commands.h"
char const* SystemCommands::clear() { return "cls"; }
char const* SystemCommands::remove() { return "erase /f/q"; }
// in sys-commands-macosx.cpp
#include "sys-commands.h"
char const* SystemCommands::clear() { return "/usr/bin/clear"; }
char const* SystemCommands::remove() { return "/bin/rm -fr"; }
Which file gets compiled will determine which command set will be used. Your application code will look like:
#include <cstdlib>
#include "sys-commands.h"
int main() {
std::system(SystemCommands::clear());
return 0;
}
Edit: I forgot to mention that I prefer static functions to global constants for a bunch of reasons. If nothing else, you can make them non-constant without changing their types - in other words, if you ever have to select the command set based on runtime settings, the user code does not have to change or even be aware that such a change occurred.
You can use a common header file and link to different modules depending on the systen:
// systemconstants.hpp
#ifndef SYSTEM_CONSTANTS_HPP_INCLUDED
#define SYSTEM_CONSTANTS_HPP_INCLUDED
namespace constants {
extern const char cls[]; // declaration of cls with incomplete type
}
#endif
In case of Linux, just compile and link to this one:
// linux/systemconstants.cpp
#include "systemconstants.hpp"
namespace constants {
extern const char cls[] = "clear";
}
In case of Windows, just compile and link to this one:
// windows/systemconstants.cpp
#include "systemconstants.hpp"
namespace constants {
extern const char cls[] = "cls";
}
System-specific translation units could be placed in specific subdirectories (linux/, windows/, etc) of which one could be automatically selected during the build process. This extends to many other things, not just string constants.