Avoiding "already defined in ..." error/warring in c++ none class variables - c++

I have global variables that I define in the Utility namespace. This utility is included in several files and it looks like this:
#ifndef _UT_
#define _UT_
namespace UT {
std::string PLATFORM_LINUX_NAME = "linux";
std::string PLATFORM_MACOSX_NAME = "macosx";
std::string PLATFORM_WINDOWS_NAME = "windows";
#if defined(OS_WIN)
int PLATFORM = OSTYPE::PLATFORM_WINDOWS;
#elif defined(OS_LINUX)
int PLATFORM = PLATFORM_LINUX;
#elif defined(OS_APPLE)
int PLATFORM = PLATFORM_MACOSX;
#endif
};
When I include this file in for example files A.h and B.h and C.h, I'm getting a compiler warning that says:
warning LNK4006: "int UT::PLATFORM" (?PLATFORM#UT##3HA) already defined in A.obj; second definition ignored
warning LNK4006: "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > UT::PLATFORM_LINUX_NAME" (?PLATFORM_LINUX_NAME#UT##3V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##A) already defined in A.obj; second definition ignored
What is the best way that does not involve creating a class for solving this?
Or is creating a UT class the only way?

Define the variables in a single .cpp file and declare them in the .h file. In UT.h:
namespace UT
{
extern const std::string PLATFORM_LINUX_NAME;
extern const std::string PLATFORM_MACOS_NAME;
extern const std::string PLATFORM_WINDOWS_NAME;
extern const int PLATFORM;
}
in UT.cpp:
namespace UT
{
const std::string PLATFORM_LINUX_NAME = "linux";
const std::string PLATFORM_MACOS_NAME = "macosx";
const std::string PLATFORM_WINDOWS_NAME = "windows";
#if defined(OS_WIN)
const int PLATFORM = OSTYPE::PLATFORM_WINDOWS;
#elif defined(OS_LINUX)
const int PLATFORM = PLATFORM_LINUX;
#elif defined(OS_APPLE)
const int PLATFORM = PLATFORM_MACOSX;
#endif
}
I added const qualifier as these appear to be constant values.

One solution is to make them all static, in which case each object file gets its own copy. Another possibility is to only put the declaration in the header and put the definitions in a separate file.

Try
#ifndef _INCL_GUARD
#define _INCL_GUARD
std::string PLATFORM_LINUX_NAME = "linux";
std::string PLATFORM_MACOSX_NAME = "macosx";
std::string PLATFORM_WINDOWS_NAME = "windows";
#if defined(OS_WIN)
int PLATFORM = OSTYPE::PLATFORM_WINDOWS;
#elif defined(OS_LINUX)
int PLATFORM = PLATFORM_LINUX;
#elif defined(OS_APPLE)
int PLATFORM = PLATFORM_MACOSX;
#endif
#endif

Related

multiple definition of a function

I defined a function to show a message when debug flags are off in a header file as below:
#ifdef NDEBUG
#define debug_msg(expr, msg) (static_cast<void>(0))
#else /* Not NDEBUG. */
#ifndef SHOW_DEBUG_H_
#define SHOW_DEBUG_H_
#include <stdio.h>
void _show_in_debug(const char *_file, unsigned int _line,
const char *_function, const char *_msg)
{
printf("%s\t%d\t%s\t%s\n", _file, _line, _function, _msg);
fflush(NULL);
}
#endif
#define debug_msg(expr, msg) \
((expr) \
? _show_in_debug(__FILE__, __LINE__, __func__, msg) \
: static_cast<void>(0))
#endif
when I include the header in more than a file, I get the following error:
multiple definition of `_show_in_debug(char const*, unsigned int, char
const*, char const*)'
I don't exactly know what I am doing wrong here, any help ?
Even with the include guards, you end up with a definition of _show_in_debug in each compilation unit. Linking those units then results to a multiple definition error.
For a debugging function like this, define the function as static so that it is not visible outside its compilation unit:
static void _show_in_debug(const char *_file, unsigned int _line,
const char *_function, const char *_msg)
{
printf("%s\t%d\t%s\t%s\n", _file, _line, _function, _msg);
fflush(NULL);
}
If you include that header into more than one .c file, each of them will define the function. That is what the error says.
What you should do is to only declare the function in the header (i.e. only put the prototype there; which you always should) and then define it in a single .c file (i.e. put the body in the .c file), encapsulated into the same switches as the prototype.
Header to be changed to this:
/* ... as you quoted ... */
void _show_in_debug(const char *_file, unsigned int _line,
const char *_function, const char *_msg);
/* ... rest of what you quoted ... */
Code file to contain this:
#incude <stdio.h>
#include "Yourheader.h"
#ifdef NDEBUG
void _show_in_debug(const char *_file, unsigned int _line,
const char *_function, const char *_msg)
{
printf("%s\t%d\t%s\t%s\n", _file, _line, _function, _msg);
fflush(NULL);
}
#endif
I assume the file header file that you have presented is included in several source files. Why is this a problem? That is because you have defined your _show_in_debug() function in the header instead of declaring it in the header and defining it in a source file file. This leads to the function be defined in multiple source files that have included your header.
See http://www.cprogramming.com/declare_vs_define.html for more details (especially, see the "Common Cases" section).

How to define a "global" struct?

Let say I've decleared this within MyTools.h
#ifndef _MYTOOLS_
#define _MYTOOLS_
typedef struct {
// const
double LN20;
double LN40;
// methods
double NoteToFrequency(int noteNumber);
} Tool;
extern const Tool tool;
#endif // !_MYTOOLS_
For every compilation unit, there is only a global/const/unique instance of Tool. Exactly what I want.
But now: how can I define it? In the .h i've only declared it. How can I define it in .cpp? Tried somethings like:
tool.LN20 = 1.34;
But of course it doesn't works. And the method's definition?
extern doesn't define any variable it just declares it. What you wan't to achieve can be done as below:
The link Global const object shared between compilation units explains how to do it with extern const
t.h file
#ifndef _MYTOOLS_
#define _MYTOOLS_
struct Tool {
// const
double LN20;
double LN40;
double NoteToFrequency(int noteNumber);
} ;
extern const Tool tool ;
#endif // !_MYTOOLS_
t1.cpp
#include "t.h"
#include <stdio.h>
void use_tool()
{
printf("%f\n",tool.LN20);
printf("%f\n",tool.LN40);
return;
}
t2.cpp
#include "t.h"
#include <stdio.h>
const Tool tool = {.LN20 = 20.0, .LN40 = 30.2};
double Tool::NoteToFrequency(int noteNumber)
{
return 12.0;
}
void use1_tool()
{
printf("%f\n",tool.LN20);
printf("%f\n",tool.LN40);
return;
}
int main()
{
void use_tool();
use_tool();
use1_tool();
return 0;
}
Hope this helps.

static variable in #define directive c++

Is it possible to declare static variable in a #define directive?
// header file
#define TEXT_ENUM
#ifdef TEXT_ENUM
#define TEXT_HANDLING_MACRO \
static const char * TEXT[]; \
static const char * getText( int _enum ) { \
return TEXT[_enum]; \
}
#else
#define TEXT_HANDLING_MACRO
#endif
struct Foo {
TEXT_HANDLING_MACRO
};
// cpp file
#include "foo.h"
const char * Foo::TEXT[] = {
"ONE",
"TWO",
"THREE",
0
};
How compiler will resolve static const char *, when I include this header file in some other file and try to access Foo::TEXT[].
Is it possible to declare static variable in a #define directive?
Yes, it is possible.
How compiler will resolve static const char *, when I include this header file in some other file and try to access Foo::TEXT[].
It's resolved at the linking stage.
You have to figure out what happens through the stages of compilations that the C compiler uses.
Since #define si a pre-compiler directive, everything will be resolved before actually compiling or looking at the code. Pieces of text (code, functions, whatever is included) will be passed on or filtered according to the directive.
All the rest happens after that, like compilation, that will look for global variable declaration, and linking, that will look for the address of those variable.
In you case, if you take your file and compile with a gcc compiler and the -E option (to do just the precompiler stage), you will get:
struct Foo {
static const char * TEXT[]; static const char * getText( int _enum ) { return TEXT[_enum]; }
};
const char * Foo::TEXT[] = {
"ONE",
"TWO",
"THREE",
0
};

Redefinition of a class in a header file

I'm attempting to compile my code with g++, but its throwing this compiler error:
Enrollment.h:3:7: error: redefinition of class sict::Enrollment
Enrollment.h:3:7: error: previous definition of class sict::Enrollment
my Enrollment.h:
namespace sict{
class Enrollment{
private:
char _name[31];
char _code[11];
int _year;
int _semester;
int _slot;
bool _enrolled;
public:
Enrollment(const char* name , const char* code, int year, int semester , int time );
Enrollment();
void set(const char* , const char* , int ,int, int , bool = false );
void display(bool nameOnly = false)const;
bool valid()const;
void setEmpty();
bool isEnrolled() const;
bool hasConflict(const Enrollment &other) const;
};
}
Any way to fix this?
The problem is likely that your header file is included (directly and indirectly) in the same translation unit. You should use some way of avoiding the multiple includes of the same header file in your cpp's. I prefer #pragma once in the beginning of your header file - it is not standard but it is supported by all major compilers. Otherwise you can go for good-old include guards:
#ifndef _Enrollment_h_
#define _Enrollment_h_
// Your header contents here
#endif
or with pragma:
#pragma once
// Your header contents here
You need to use some include guards. Either #pragma once or:
#ifndef MY_FILE_H
#define MY_FILE_H
....
#endif //MY_FILE_H
This is to prevent the same code being included in every file where you include this header (double inclusion). This will essentially help out the pre-processor. More information here.

Undefined reference when using extern on a c++ object, but not integral type

I'm getting undefined reference errors when trying to use extern on a c++ object. It doesn't appear to happen with integral types. What am I missing?! This code below replicates the problem:
file1.cpp:
#include <string>
const std::string s("test");
int i = 99;
int main()
{
extern void Test();
Test();
}
file2.cpp:
#include <iostream>
#include <string>
extern const std::string s;
extern int i;
void Test()
{
std::cout << s << std::endl;
std::cout << i << std::endl;
}
if i comment out the usage of the 's' std::string variable, the linking errors go away.
There are other questions on SO similar to this, but they all seem to be related to people not defining the variable, which I am!
It's the const on std::string, it gives s internal linkage. Quote from [3.5 Program and linkage]:3:
A name having namespace scope (3.3.6) has internal linkage if it is
the name of
— a variable that is explicitly declared const or constexpr and
neither explicitly declared extern nor previously declared to have
external linkage; or
If you remove const, it works in vc++, and if you define them both extern const, it also works.
// file1.cpp
extern const std::string s("test");
extern const int i = 99;
// file2.cpp
extern const std::string s;
extern const int i;
If you remove any 'extern' from file1.cpp, it can't compile. If the variables are defined const, you can remove 'extern' from file1.cpp.