This question already has answers here:
Why does global variables in a header file cause link error?
(5 answers)
Closed 7 years ago.
I know, there are a lot of similar problems and solutions already on SO, and I read them, but none of them helped me solve my problem.
I created a class for logging.
Here is Logger.h
#ifndef LOGGER_H
#define LOGGER_H
namespace Logger
{
namespace debug
{
int Error = 0, OtherNumber;
class log
{
public: // Methods
void Save();
private: // Members
static int indentation;
const std::wstring context;
int Type, LineNumber;
public: // Constructor, Destructor
log( const std::wstring& context, int LineNumber, int Type );
~log();
};//class log
}//namespace debug
}//namespace Logger
#endif //LOGGER_H
Logger.cpp
#include "stdafx.h"
#include "Logger.h"
namespace Logger
{
namespace debug
{
log::log( const std::wstring& ctx, int linenr, int type ): context( ctx ), LineNumber( linenr ), Type( type )
{
printf("\nLogging start! Context = %ls - Line = %d - Type = %d", context.c_str(), LineNumber, Type );
}
log::~log()
{
printf( "\nLogging end! Context = %ls - Line = %d - Type = %d", context.c_str(), LineNumber, Type );
printf( "\nUsing Error here =%d", Error );
}
void log::Save()
{
FILE *fp = NULL;
fclose( fp );
fp = fopen( "mylogfile.log", "a" );
}
}//namespace debug
}//namespace Logger
Then in main.h I have:
#ifndef MYAPP_H
#define MYAPP_H
#include "Logger.h"
#define WIDEN2( x ) L ## x
#define WIDEN( x ) WIDEN2( x )
#define WFILE WIDEN( __FILE__ )
#define __STR2WSTR( str ) L##str
#define _STR2WSTR(str) __STR2WSTR(str)
#define WFUNCTION _STR2WSTR( __FUNCTION__ )
#define DEBUGLOG_START( Type ) Logger::debug::log _debugLog( WFUNCTION, __LINE__, Type );
#define DEBUGLOG_SAVE { _debugLog.Save(); }
#endif //MYAPP_H
And finally in main.cpp I have:
#include "Test_UserPart.h"
int _tmain(int argc, _TCHAR* argv[])
{
DEBUGLOG_START( 1 )
Logger::debug::OtherNumber = 10;
_getch();
return 0;
}
When I want to compile it I get the error error LNK2005: "int Logger::debug::Error" (?Error#debug#Logger##3HA) already defined in Logger.obj ...MyApp.obj
So as far as I see, I didn't make any circular includes. But why do I get this error?
Thanks!
You're defining variables in the header, leading to multiple definitions when that header is included from more than one source file. Instead, declare them in the header:
extern int Error = 0, OtherNumber;
^^^^^^
and define them in just one source file. Or stop using global variables.
Related
I get the following error:
"Symbol SBPTest multiply defined (by ../../build/typeFind.LPC1768.o and ../../build/main.LPC1768.o)."
I have declared SBPTest in common.h like this:
#ifndef COMMON_H_
#define COMMON_H_
extern RawSerial SBPTest(USBTX, USBRX);
#endif
Other files look like this...
typeFind.h:
#include "mbed.h"
#include <string>
extern unsigned int j;
extern unsigned int len;
extern unsigned char myBuf[16];
extern std::string inputStr;
void MyFunc(char* inputBuffer);
typeFind.cpp:
#include "typeFind.h"
#include "common.h"
void MyFunc(char* inputBuffer) {
inputStr = inputBuffer;
if (inputStr == "01") {
len = 16;
for ( j=0; j<len; j++ )
{
myBuf[j] = j;
}
for ( j=0; j<len; j++ )
{
SBPTest.putc( myBuf[j] );
}
}
}
main.cpp:
#include "typeFind.h"
#include "common.h"
#include "stdlib.h"
#include <string>
LocalFileSystem local("local"); // define local file system
unsigned char i = 0;
unsigned char inputBuff[32];
char inputBuffStr[32];
char binaryBuffer[17];
char* binString;
void newSBPCommand();
char* int2bin(int value, char* buffer, int bufferSize);
int main() {
SBPTest.attach(&newSBPCommand); //interrupt to catch input
while(1) { }
}
void newSBPCommand() {
FILE* WriteTo = fopen("/local/log1.txt", "a");
while (SBPTest.readable()) {
//signal readable
inputBuff[i] = SBPTest.getc();
//fputc(inputBuff[i], WriteTo);
binString = int2bin(inputBuff[i], binaryBuffer, 17);
fprintf (WriteTo, "%s\n", binString);
inputBuffStr[i] = *binString;
i++;
}
fprintf(WriteTo," Read input once. ");
inputBuffStr[i+1] = '\0';
//fwrite(inputBuff, sizeof inputBuffStr[0], 32, WriteTo);
fclose(WriteTo);
MyFunc(inputBuffStr);
}
char* int2bin(int value, char* buffer, int bufferSize)
{
//..................
}
I am programming on mbed, a LPC1768. The serial is used both in main.cpp and typeFind.cpp. I have looked on stack overflow and a common.h file is recommended, yet I get a compiler error.
You musn't define the variable in the header, or else you end up defining it in all translation units that include the header, which violates the one definition rule. Only declare it:
// common.h
extern RawSerial SBPTest;
And define in exactly one source file:
// common.cpp (or any other, but exactly one source file)
RawSerial SBPTest(USBTX, USBRX);
I recommend using either list initialisation or copy initilisation, since direct initilisation grammar is ambiguous with a function declaration and may confuse anyone who doesn't know whether USBTX and USBRX are types or values:
// common.cpp (or any other, but exactly one source file)
RawSerial SBPTest{USBTX, USBRX}; // this
auto SBPTest = RawSerial(USBTX, USBRX); // or this
MainGame.h
#ifndef MainGame_h
#define MainGame_h
#include <string>
#include <sstream>
#include "Horde3D.h"
//definitions
#endif MainGame_h
MainGame.cpp
#include <math.h>
#include <iomanip>
#include "Horde3DUtils.h"
#include "MainGame.h"
#include "GameConfig.h" //<--
//code
main.cpp
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include "glfw.h"
#include "MainGame.h"
#include "GameConfig.h" //<--
//code
GameConfig.h
#ifndef GameConfig_h
#define GameConfig_h
#include <string>
#include <sstream>
#define MAX_PATH 260
class GameConfig
{
static std::string ExtractStartupPath(char *full_app_path)
{
const std::string s(full_app_path);
if(s.find( "/" ) != std::string::npos)
return s.substr( 0, s.rfind( "/" )) + "/";
else if(s.find( "\\" ) != std::string::npos )
return s.substr( 0, s.rfind( "\\" )) + "\\";
else
return "";
}
public:
static bool IsFullScreen;
static int StatMode;
static int FreezeMode;
static bool DebugViewMode;
static bool WireframeMode;
static char *GameTitle;
static int WindowWidth, WindowHeight;
static char StartupPath[MAX_PATH];
static char ContentPath[MAX_PATH];
static void Initialize(char *startup_path)
{
GameTitle = "TestGame\0";
std::string startup_dir = ExtractStartupPath(startup_path);
memcpy(StartupPath, startup_dir.c_str(), startup_dir.length() * sizeof(char));
std::string path(StartupPath);
path.erase(path.find_last_of('\\'), std::string::npos);
path.append("\\Content");
memcpy(ContentPath, path.c_str(), path.length() * sizeof(char));
}
};
int GameConfig::StatMode = 0;
int GameConfig::FreezeMode = 0;
bool GameConfig::DebugViewMode = false;
bool GameConfig::WireframeMode = false;
bool GameConfig::IsFullScreen = false;
int GameConfig::WindowWidth = 800;
int GameConfig::WindowHeight = 600;
char GameConfig::StartupPath[MAX_PATH] = { 0 };
char GameConfig::ContentPath[MAX_PATH] = { 0 };
char *GameConfig::GameTitle = "TestGame\0";
#endif GameConfig_h
When compiling it I getting linker errors...
main.obj : error LNK2005: "public: static int GameConfig::StatMode" (?StatMode#GameConfig##2HA) is already define in в MainGame.obj
But I don't understand why... There are only two includes of GameConfig - one in MainGame.cpp and second in main.cpp. Those should never cross. And even if they crossed, what #ifndef GameConfig_h, #define GameConfig_h and #endif GameConfig then for?
I use VC++ 2010 Express Edition
Include guards help you avoid including the same file more than once from the same translation unit. However, since the translation units are processed independently, both of them will get the included code, and therefore produce duplicate definitions.
To avoid this problem you need to move definitions out of the header and into a CPP file:
GameConfig.cpp:
#include "GameConfig.h"
int GameConfig::StatMode = 0;
int GameConfig::FreezeMode = 0;
bool GameConfig::DebugViewMode = false;
bool GameConfig::WireframeMode = false;
bool GameConfig::IsFullScreen = false;
int GameConfig::WindowWidth = 800;
int GameConfig::WindowHeight = 600;
char GameConfig::StartupPath[MAX_PATH] = { 0 };
char GameConfig::ContentPath[MAX_PATH] = { 0 };
char *GameConfig::GameTitle = "TestGame\0";
You need to move initialisation of the statics to GameConfig.cpp.
Each source file which includes GameConfig.h is picking up a their own copy of these variables at present.
The instanciations of your static members shouldn't be in the .h file but in the corresponding .cc file.
Otherwise they are instantiated in every compilation unit.
Include guards are only useful inside a single compilation unit (ie one single cpp file). Since the cpp files are compiled separately, for each file the include guard will start as undefined and therefore the .h file will be included twice, once for each cpp file. If the .h file includes for example a function definition, it will be defined twice.
Normally you make the problem "go away" by putting only declarations in the h files, and actually defining the functions in cpp files. That way, the function will only be defined once.
I'm trying to create a cross-platform program. I just created a class and made a function which gets the path of the current user. I wanted to use that path later. But somehow I get these errors :
"/usr/include/x86_64-linux-gnu/sys/stat.h:-1: In member function 'void FileManager::p_getfilepath()':"
"/usr/include/x86_64-linux-gnu/sys/stat.h:105: error: expected unqualified-id before string constant"
"/home/david/VocabularyTrainer/filemanager.cpp:31: error: expected '}' at end of input"
btw the 31th line is the last line here in this code :
void FileManager::p_getfilepath()
{
#ifdef Q_OS_WIN32
#include <windows.h>
#endif
#ifdef Q_OS_LINUX
#include <sys/stat.h>
struct passwd *p;
uid_t uid;
if ((p = getpwuid(uid = geteuid())) == NULL)
{
QMessageBox* mb;
mb->setText("");
mb->exec();
delete mb;
}
else
{
filepath = p->pw_dir;
}
#endif
}
Anyone knows what's wrong? I'm on linux mint.
By including your headers inside your class functions, you're making everything in the header a part of the function.
#ifdef Q_OS_WIN32
#include <windows.h>
#endif
#ifdef Q_OS_LINUX
#include <sys/stat.h>
#endif
void FileManager::p_getfilepath()
{
#ifdef Q_OS_LINUX
struct passwd *p;
uid_t uid;
if ((p = getpwuid(uid = geteuid())) == NULL)
{
QMessageBox* mb;
mb->setText("");
mb->exec();
delete mb;
}
else
{
filepath = p->pw_dir;
}
#endif
}
I have a visual studio c++ project (with VS 2010 and insight 2) which contains a cuda file. Here's the code
Hello.h :
#pragma once
#pragma warning(push)
#pragma warning(disable:4996)
#include "thrust\device_vector.h"
#pragma warning(pop)
class Hello
{
public:
Hello( const thrust::host_vector<unsigned long>& data );
unsigned long Sum();
unsigned long Max();
private:
thrust::device_vector<unsigned long> m_data;
}
Hello.cu :
#include "thrust\host_vector.h"
#include "thrust\device_vector.h"
#include "thrust\extrema.h"
#include "Hello.h"
using namespace ::thrust;
Hello::Hello( const thrust::host_vector<unsigned long>& data )
: m_data( data.cbegin(), data.cend() )
{
}
unsigned long
Hello::Sum()
{
return( reduce( m_data.cbegin(), m_data.cend(),
( unsigned long )0,
plus<unsigned long>() ) );
}
unsigned long
Hello::Max()
{
return( *max_element( m_data.cbegin(), m_data.cend() ) );
}
and finally main.cpp :
#ifdef _WIN32
#define WINDOWS _LEAN_AND_MEAN
#define NOMINMAX
#include <Windows.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ppl.h> //parallel patterns library
#include "Hello.h"
using namespace ::Concurrency;
int
main( int argc, char** argv )
{
printf( "Generating data...\n" );
thrust::host_vector<unsigned long> host_data( 100000 );
thrust::generate( host_data.begin(), host_data.end(), rand );
printf( "generated %d numbers\n", host_data.size() );
parallel_invoke(
[host_data]()
{
printf( "\nRunning host code...\n" );
unsigned long host_result = thrust::reduce( host_data.cbegin(),
host_data.cend(), 0, thrust::plus<unsigned long>() );
printf( "The sum is %d\n", host_result );
host_result = *thrust::max_element( host_data.cbegin(),
host_data.cend(), thrust::less<unsigned long>() );
printf( "The max is %d\n", host_result );
},
[host_data]()
{
printf( "\nCopying data to device...\n" );
Hello hello( host_data );
printf( "\nRunning CUDA device code...\n" );
unsigned long device_result = hello.Sum();
printf( "The sum is %d\n", device_result );
printf( "\nRunning CUDA device code...\n" );
device_result = hello.Max();
printf( "The max is %d\n", device_result );
}
);
return( 0 );
}
This code comes from : here
My problem is that when I build the project, it gives me this error:
Hello.cu(5): fatal error C1083: Cannot open include file: 'Hello.h': No such file or directory
However, when I right click on the "include "Hello.h"" it finds the file just fine.
I've added the folder where my .h are in the additionnal include directories of the project. So I really don't know why it couldn't open the file.
I don't know if it's more of a configuration problem of just maybe a c++ thing I forgot...
Your .cu file will have most likely have a custom build rule to make use of NVCC. Right-click the .cu file and look at its properties. The build rule will again contain a section for additional include directories. Make sure the directory containing your header is present there as well.
OKay, so I'm trying to set some global variables that can be accessed by the rest of my program by including a header file. However, XCode is telling me that I have duplicate symbols. Can anyone help?
Error: Duplicate symbol _ArrowKey in /Path/to/MKDBControlInterface.o /Path/to/main.o
main.h: // The global variables to be accessed...
#ifndef _main_h
#define _main_h
#include <map>
std::map<int,bool> ArrowKey;
#endif
MKDBControlInterface.h:
#ifndef _MKDBControlInterface_h
#define _MKDBControlInterface_h
#include <map>
#include <GLUT/glut.h>
#include "main.h"
#include "MKDBApplication.h"
class MKDBControlInterface {
public:
MKDBControlInterface( MKDBApplication& App )
: m_App( App )
{
glutSpecialFunc( SpecialListener );
glutSpecialUpFunc( SpecialListenerX );
ArrowKey[GLUT_KEY_LEFT] = false;
ArrowKey[GLUT_KEY_RIGHT] = false;
ArrowKey[GLUT_KEY_UP] = false;
ArrowKey[GLUT_KEY_DOWN] = false;
}
~MKDBControlInterface(){}
void static SpecialListener( int key, int x, int y ){
ArrowKey[key] = true;
}
void static SpecialListenerX( int key, int x, int y ){
ArrowKey[key] = false;
}
private:
MKDBApplication& m_App;
};
#endif
main.cpp
#include "main.h"
#include "MKDBApplication.h"
#include "MKDBControlInterface.h"
#include "MKDBRender.h"
int main( int argc, char *argv[] ){
MKDBApplication App;
MKDBControlInterface Interface( App );
MKDBRender Render( App );
return 0;
}
In main.h you need to declare ArrowKey as
extern "C" std::map<int,bool> ArrowKey;
and in main.cpp after the includes you should define it:
std::map<int,bool> ArrowKey;
BTW, I would also replace #ifndef/#define/#endif with #pragma once in the headers.